- Modern C++:Efficient and Scalable Application Development
- Richard Grimes Marius Bancila
- 653字
- 2021-06-10 18:28:14
Destructing objects
When an object is destroyed, a special method called the destructor is called. This method has the name of the class prefixed with a ~ symbol and it does not return a value.
If the object is an automatic variable, on the stack, then it will be destroyed when the variable goes out of scope. When an object is passed by value, a copy is made on the called function's stack and the object will be destroyed when the called function completes. Furthermore, it does not matter how the function completes, whether an explicit call to return or reaching the final brace, or if an exception is thrown; in all of these cases, the destructor is called. If there are multiple objects in a function, the destructors are called in the reverse order to the construction of the objects in the same scope. If you create an array of objects, then the default constructor is called for each object in the array on the statement that declares the array, and all the objects will be destroyed--and the destructor on each one is called, when the array goes out of scope.
Here are some examples, for a class mytype:
void f(mytype t) // copy created
{
// use t
} // t destroyed
void g()
{
mytype t1;
f(t1);
if (true)
{
mytype t2;
} // t2 destroyed
mytype arr[4];
} // 4 objects in arr destroyed in reverse order to creation
// t1 destroyed
An interesting action occurs when you return an object. The following annotation is what you would expect:
mytype get_object()
{
mytype t; // default constructor creates t
return t; // copy constructor creates a temporary
} // t destroyed
void h()
{
test tt = get_object(); // copy constructor creates tt
} // temporary destroyed, tt destroyed
In fact, the process is more streamlined. In a debug build, the compiler will see that the temporary object created on the return of the get_object function is the object that will be used as the variable tt, and so there is no extra copy on the return value of the get_object function. The function actually looks like this:
void h()
{
mytype tt = get_object();
} // tt destroyed
However, the compiler is able to optimize the code further. In a release build (with optimizations enabled), the temporary will not be created and the object tt in the calling function will be the actual object t created in get_object.
An object will be destroyed when you explicitly delete a pointer to an object allocated on the free store. In this case, the call to the destructor is deterministic: it is called when your code calls delete. Again, with the same class mytype, this is as follows:
mytype *get_object()
{
return new mytype; // default constructor called
}
void f()
{
mytype *p = get_object();
// use p
delete p; // object destroyed
}
There will be times when you want to use the deterministic aspect of deleting an object (with the possible danger of forgetting to call delete) and there will be times when you prefer to have the reassurance that an object is to be destroyed at an appropriate time (with the potential that it may be much later in time).
If a data member in a class is a custom type with a destructor, then when the containing object is destroyed the destructors on the contained objects are called too. Nonetheless, note that this is only if the object is a class member. If a class member is a pointer to an object in the free store, then you have to explicitly delete the pointer in the containing object's destructor. However, you need to know where the object the pointer points to is because if it is not in the free store, or if the object is used by other objects, calling delete will cause problems.