假设我有一个班级
class A { public: A(int i); ~A(); private: B b; // Want <- this guy to be constructed with i in A's constructor! };我希望b在构造函数中构造,具有在构造A之前不知道的特定参数。如果我在A的构造函数中执行以下操作:
A::A(int i) { B b(i); // Or even if I try to do b = B::B(i); }
我注意到b在堆栈上被分配了两次! aghghg。
然后我发现我在A的构造函数中可以做的是:
A::A() : b(B::B(7)) { }
b只能在堆栈上分配一次!
但这非常笨重。谁有更好的主意?请记住,构造函数只应调用一次!
这是使用重要参数非动态分配对象的标准方法吗?如果我们能把b的结构推到那个花哨的参数列表中,那该怎么办?你被迫在堆栈上动态分配或构建TWICE!
奖金问题:什么时候被解除分配?它是在A的析构函数之后还是之前
答案 0 :(得分:7)
我很遗憾地说,但你错了。
您需要做的是选择good beginner's C++ book。这是语言的一个基本部分,如果你不理解这一点,你在处理非平凡的C ++代码时会很困难。
话虽这么说,当即将创建一个对象时,将首先创建所有子对象。如果需要将参数传递给这些子对象构造函数,则需要创建所谓的初始化列表:
A::A(int i) : b(i) {}
冒号后面和第一个大括号之前的东西是初始化列表。只有构造函数才能拥有它们。这里发生的是我们将i
的值传递给b
子对象的构造函数。在调用A
的构造函数之前发生!
因此,对于您的情况,构造顺序为:
b
子对象A
对象本身破坏的顺序是完全相反的过程。
答案 1 :(得分:3)
确实
A::A() : b(7) { }
不起作用?
编辑:我正在工作,所以我稍后会使用一些配置文件来进行更全面的编辑,以了解gcc的功能w.r.t.释放。我怀疑nobar是对的,所有的释放都会立即发生。
b(B::B(7))
与b(7)
一样有效,因为B::B(7)
会创建一个临时B
变量。然后从该临时文件复制构造b
。一个不错的优化编译器应该能够将第二种情况减少到第一种情况,但是:
b(7)
更具惯用性 - 其他c ++程序员将更容易识别B
不是可复制构造的,或者复制构造成本高,那么如果像大多数情况一样,关闭优化以进行调试,则可能不想处理增加的开销。答案 2 :(得分:0)
只需要对程序进行一些小修改即可演示构造和销毁的顺序。
#include <iostream>
using std::cerr;
class B
{
public:
B( int ) { cerr<<"B()\n"; ;}
~B() { cerr<<"~B()\n"; }
};
class A
{
B b;
public:
A( int i ) : b(i) { cerr<<"A()\n"; }
~A() { cerr<<"~A()\n"; }
};
int main()
{
A a(7);
}
这是输出:
$ make destructor_order && ./destructor_order
B()
A()
~A()
~B()