In Stroustrup's book The C++ Programming language, He mentions "It is typically important that resources are released in the reverse order of their acquisition" why the order is important?
void acqu开发者_运维百科ire()
{
acquire resource 1;
...
acquire resource n;
use resources;
release resource n;
...
release resource 1;
}
so what if we change the order as follow?
void acquire()
{
acquire resource 1;
...
acquire resource n;
use resources;
release resource 1;
...
release resource n;
}
If you don't you can get into a deadlock or leak situation. Say that you declare Obj1 and it allocates Obj2-Obj3. You have to have 2 and 3 freed before you can free 1. In practice though this is not something to worry about because constructores and destructors will get called in the right order.
One reason is you usually have nested memory allocations.
E.g. you have a class
class A{
FILE *fp;
char *name;
xxx;
}
you first allocate the resource for A using new A
, and later you need to manipulate A's fp
and name
. So when you release the resource, you need to release fp
and name
first, then A
.
In the most general sense, "it only matters if it matters." Dependencies dictate the necessary order of destruction.
The existing answers here relate to releasing nested resources in reverse topological order.
But also, C++ defines the order that resources within an object are initialized. That means that member construction can use previously initialized "brothers and sisters"… meaning they have dependencies and those siblings should still be valid at destruction.
class A {
A( std::string *link2str );
~A();
std::string *important_state;
};
class B {
string first; // initialization occurs in the order of declaration
A second;
B() : first(), second( &first ) { } // not the constructor's list order
};
Not that this example looks like a good design, but you never know. Sometimes there is a reason for some kind of dependency between members.
Resources, in real-world code, will typically be nested, and you want anything available when constructing an object to be available when destroying it. Since C++ has deterministic destruction it must pick some ordering, and FILO ("first in, last out") works well.
The simplest example of nesting is classes. They are always constructed by first constructing bases, then members, then the derived ctor's body:
struct Base {
Base() { cout << "Base\n"; }
};
struct Member {
Member() { cout << "Member\n"; }
};
struct Derived : Base {
Member member;
Derived() { cout << "Derived\n"; }
};
Now you can add similar output dtors to this example.
You can't destroy Base before Derived has been destroyed (Derived's dtor might need to use it, among other issues); same for member.
精彩评论