When you say:
{
Foo f; // memory allocated & default constructor called
} // destructor called and memory deallocated
C++ allocates enough memory on the stack the size of Foo, and calls Foo's default constructor, giving those bits an identity (Foo). When it goes out of scope, it calls the destructor and deallocates that memory.
Same thing happens with creating objects dynamically on the heap...
Foo* p = new Foo; // memory allocated & default constructor called
Except now, you have to explicitly delete this object...
delete p; // destructor called & memory deallocated
The interesting thing is that there is a difference between keyword new and operator new. operator new is responsible for allocating the memory, while keyword new calls the constructor. So, you could call operator new directly and NOT have the constructor called.
Foo* p = static_cast
This will allocate memory on the heap for a Foo WITHOUT constructing it.
What's the point? Well, not much when you're dealing with individual objects, but they come in handy with arrays of objects.
Consider this line...
Foo* p = new Foo[ 10 ];
This will not only allocate memory for 10 Foos, but also call the default constructor for each of those Foo's. Allocation takes place in constant time O(1), initialization is linear O(N).
What if you wanted a different constructor to be called for each object? What if you didn't want the default? There is no way to specify which constructor you want called when dealing with arrays. You'd have an array of 10 default constructed Foos. You would then have to traverse it, delete those objects, create newly constructed individual objects and assign it to each index.
This is where operator new comes into play.
Foo* p = static_cast
for ( int i = 0; i < 10; ++i )
{
new ( &p[ i ] ) Foo( 1, 2 );
}
The first line allocates memory for 10 Foos. That's all it does. The loop goes through each index of the array and constructs a Foo with a 2 argument constructor.
The Standard Template Library actually has a class called allocator which encapsulates this functionality. Methods on that class are allocate(), construct(), destory() and deallocate().
So you can do something like...
Foo* p = allocator.allocate( 10 ); // allocate memory for 10 Foos
for ( int i = 0; i < 10; ++i )
{
allocator.construct( &p[ i ], Foo( 1, 2 ) ); // construct Foo with two argument constructor
}
for ( int i = 0; i < 10; ++i )
{
allocator.destroy( &p[ i ] ); // destroy Foo
}
allocator.deallocate( p ); // deallocate memory
There are a ton of minute details like this in C++. Because it gives you so much control it is such an interesting language.
1 comment:
good and useful article, but maybe there had to be:
Foo* p = static_cast< Foo * >( operator new( sizeof( Foo ) ) );
instead of:
Foo* p = static_cast( operator new( sizeof( Foo ) ) );
?
at least, GCC doesn't understand yours example. thanks for article once more, good bye.
Post a Comment