在堆栈上创建c ++对象,努力不要分配

时间:2010-10-12 03:31:02

标签: c++ memory-management

假设我有一个班级

    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的析构函数之后还是之前

3 个答案:

答案 0 :(得分:7)

我很遗憾地说,但你错了。

您需要做的是选择good beginner's C++ book。这是语言的一个基本部分,如果你不理解这一点,你在处理非平凡的C ++代码时会很困难。

话虽这么说,当即将创建一个对象时,将首先创建所有子对象。如果需要将参数传递给这些子对象构造函数,则需要创建所谓的初始化列表:

A::A(int i) : b(i) {}

冒号后面和第一个大括号之前的东西是初始化列表。只有构造函数才能拥有它们。这里发生的是我们将i的值传递给b子对象的构造函数。在调用A的构造函数之前发生

因此,对于您的情况,构造顺序为:

  1. b子对象
  2. A对象本身
  3. 破坏的顺序是完全相反的过程。

答案 1 :(得分:3)

确实

A::A() : b(7) { }

不起作用?

编辑:我正在工作,所以我稍后会使用一些配置文件来进行更全面的编辑,以了解gcc的功能w.r.t.释放。我怀疑nobar是对的,所有的释放都会立即发生。

b(B::B(7))b(7)一样有效,因为B::B(7)会创建一个临时B变量。然后从该临时文件复制构造b。一个不错的优化编译器应该能够将第二种情况减少到第一种情况,但是:

  1. b(7)更具惯用性 - 其他c ++程序员将更容易识别
  2. 你真的不确定编译器会做什么。
  3. 如果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()