在Stroustrup的“C ++编程语言”一书中,他提到“资源以与其收购相反的顺序发布通常很重要” 为什么订单很重要?
void acquire()
{
acquire resource 1;
...
acquire resource n;
use resources;
release resource n;
...
release resource 1;
}
那么如果我们改变订单如下呢?
void acquire()
{
acquire resource 1;
...
acquire resource n;
use resources;
release resource 1;
...
release resource n;
}
答案 0 :(得分:4)
如果不这样做,您可能陷入僵局或泄密状态。假设您声明Obj1并且它分配Obj2-Obj3。你必须释放2和3才能释放1.在实践中虽然这不用担心,因为构造函数和析构函数将按正确的顺序调用。
答案 1 :(得分:3)
一个原因是您通常拥有嵌套的内存分配。
E.g. you have a class
class A{
FILE *fp;
char *name;
xxx;
}
您首先使用new A
为A分配资源,之后您需要操纵A的fp
和name
。因此,当您发布资源时,您需要首先发布fp
和name
,然后发布A
。
答案 2 :(得分:1)
从最普遍的意义上讲,“只有重要才重要”。依赖性决定了必要的破坏顺序。
此处的现有答案涉及以反向拓扑顺序释放嵌套资源。
但是,C ++还定义了对象内资源的初始化顺序。这意味着会员建设可以使用以前初始化的“兄弟姐妹”......这意味着他们有依赖关系,而这些兄弟姐妹在销毁时仍然有效。
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
};
不是说这个例子看起来像一个好的设计,但你永远不会知道。 有时成员之间存在某种依赖性的原因。
答案 3 :(得分:0)
实际代码中的资源通常是嵌套的,并且在构建对象时,您希望在销毁它时可用的任何内容。由于C ++具有确定性破坏,因此必须选择一些排序,而FILO(“先进先出”)运行良好。
最简单的嵌套示例是类。它们总是通过首先构建基础,然后是成员,然后是衍生的ctor的身体来构建:
struct Base {
Base() { cout << "Base\n"; }
};
struct Member {
Member() { cout << "Member\n"; }
};
struct Derived : Base {
Member member;
Derived() { cout << "Derived\n"; }
};
现在您可以在此示例中添加类似的输出dtors。
你不能在Derived被销毁之前销毁Base(Derived的dtor可能需要使用它,以及其他问题);会员也一样。