What are the dynamics of the C++ delete statement?
This is merely for curiosity sake because I have not used new
and delete
in c++ except for the most basic uses.
I know that delete
releases memory. The thing I'm wondering is how does it handle more complex cases?
For instance, if I have a user-defined class like this:
class MyClass
{
publ开发者_运维百科ic:
MyClass();
~MyClass()
{
delete [] intArray;
}
//public members here
private:
int* intArray;
};
Assuming the class allocates memory somehow for intArray
, and then release it in the destructor, What if I used the class like this: MyClass* myClass = new MyClass();
and released it later with delete myclass;
How does delete
handle the releasing of all the memory? Does the class destructor get called first to release all of the memory allocated by the class (ie int* intArray
) and then release the memory allocated to hold the class?
What if I had a class like this:
class MyClass
{
public:
MyClass();
~MyClass()
{
delete anotherMyClass;
}
//public members here
private:
MyClass* anotherMyClass;
};
Assuming anotherMyClass
is not allocated with the constructor, which would use up memory very quickly, what if there was a chain of MyClasses attached to each other like a linked-list? Would the delete statement in the destructor work in this case? Would each anotherMyClass
be recursively released when the destructor gets called?
Are there any specific weird tricks or caveats with the new
and delete
statements that you know about?
Given a pointer (p
) to a dynamically allocated object, delete
does two things:
- It calls the destructor of the dynamically allocated object. Note that when
~MyClass()
completes, the destructors for any member variables of class type are called. - It frees the memory occupied by the dynamically allocated object.
It doesn't search the member variables of the object for other pointers to free; it doesn't free any other memory and doesn't do anything else.
If you need to free the memory pointed to by intArray
, you need to delete
it in the destructor of MyClass
.
However, in almost all C++ code, you don't need to worry about this. You should be using smart pointers like shared_ptr
, unique_ptr
, auto_ptr
, and scoped_ptr
to automatically manage dynamically allocated objects. Manual resource management is difficult at best and should be avoided wherever possible.
This is part of a broader idiom, Scope-Bound Resource Management (SBRM, also called Resource Acquisition is Initialization, or RAII). This is by far the most important design pattern to understand and to use everywhere in your C++ code.
If in your class you had declared this instead:
boost::scoped_ptr<int> intArray;
then when the scoped_ptr<int>
object is destroyed, it will free the pointer that it holds. You then do not have to do any work to manually destroy the object.
In well-written, modern C++ code, you should rarely need to manually use delete
. Smart pointers and other SBRM containers should be used to manage any type of resource that needs cleanup, including dynamically allocated objects.
In your second example, given a linked list that looks like:
x -> y -> z -> 0
you would have an order of operations that looks like this:
delete x;
x.~MyClass();
delete y;
y.~MyClass();
delete z;
z.~MyClass();
delete 0;
[free memory occupied by z]
[free memory occupied by y]
[free memory occupied by x]
The objects in the linked list would be destroyed in reverse order.
delete intArray;
I assume intArray
points to the first element of an int
array? In that case, delete intArray
yields undefined behavior. If you allocate via new[]
, you must release via delete[]
.
delete[] intArray;
Yes I know, delete intArray
might appear to work just fine on certain systems with certain compiler versions under certain compiler options -- or it might not. That's undefined behavior for ya.
Also, you should follow the Rule of Three. Defining your own destructor but relying on the implicitly-defined copy constructor and copy assignment operator is a recipe for disaster.
精彩评论