开发者

Is memory released when a destructor is called or when `delete` is called?

Assume you have an 开发者_C百科object of class Fool.

class Fool
{
    int a,b,c;
    double* array ;
    //...
    ~Fool()
    {
        // destroys the array..
        delete[] array ;
    }
};


Fool *fool = new Fool() ;

Now, I know you shouldn't, but some fool calls the destructor on fool anyway. fool->~Fool();.

Does that mean fool's memory is freed, (ie a,b,c are invalid) or does that mean only whatever deallocations in ~Fool() function occur (ie the array is deleted only?)

So I guess my question is, is a destructor just another function that gets called when delete is called on an object, or does it do more?


If you write

fool->~Fool();

You end the object's lifetime, which invokes the destructor and reclaims the inner array array. The memory holding the object is not freed, however, which means that if you want to bring the object back to life using placement new:

new (fool) Fool;

you can do so.

According to the spec, reading or writing the values of the fields of fool after you explicitly invoke the destructor results in undefined behavior because the object's lifetime has ended, but the memory holding the object should still be allocated and you will need to free it by invoking operator delete:

fool->~Fool();
operator delete(fool);

The reason to use operator delete instead of just writing

delete fool;

is that the latter has undefined behavior, because fool's lifetime has already ended. Using the raw deallocation routine operator delete ensures that the memory is reclaimed without trying to do anything to end the object's lifetime.

Of course, if the memory for the object didn't come from new (perhaps it's stack-allocated, or perhaps you're using a custom allocator), then you shouldn't use operator delete to free it. If you did, you'd end up with undefined behavior (again!). This seems to be a recurring theme in this question. :-)

Hope this helps!


The destructor call does just that, it calls the destructor. Nothing more and nothing less. Allocation is separate from construction, and deallocation from destruction.

The typical sequence is this:

1. Allocate memory
2. Construct object
3. Destroy object  (assuming no exception during construction)
4. Deallocate memory

In fact, if you run this manually, you will have to call the destructor yourself:

void * addr = ::operator new(sizeof(Fool));
Fool * fp = new (addr) Fool;
fp->~Fool();
::operator delete(addr);

The automatic way of writing this is of course Fool * fp = new Fool; delete fp;. The new expression invokes allocation and construction for you, and the delete expression calls the destructor and deallocates the memory.


Does that mean fool's memory is freed, (ie a,b,c are invalid) or does that mean only whatever deallocations in ~Fool() function occur (ie the array is deleted only?)

Fool::~Fool() has zero knowledge about whether the Fool instance is stored in dynamic storage (via new) or whether it is stored in automatic storage (i.e. stack objects). Since the object ceases to exist after the destructor is run, you can't assume that a, b, c and array will stay valid after the destructor exits.

However, because Fool::~Fool() knows nothing about how the Fool was allocated, calling the destructor directly on a new-allocated Fool will not free the underlying memory that backs the object.


You should not access a, b, and c after the destructor is called, even if it's an explicit destructor call. You never know what your compiler puts in your destructor that might make those values invalid.

However, the memory is not actually freed in the case of an explicit destructor call. This is by design; it allows an object constructed using placement new to be cleaned up.

Example:

char buf[sizeof (Fool)];
Fool* fool = new (buf) Fool;  // fool points to buf
// ...
fool->~Fool();


The easiest place to see that the destructor is distinct from deallocation via delete is when the allocation is automatic in the first place:

{
  Fool fool;
  // ~Fool called on exit from block; nary a sign of new or delete
}

Note also the STL containers make full use of the explicit destructor call. For example, a std::vector<> treats storage and contained objects lifetime quite separately.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜