重新分配变量时,不会调用析构函数。(C ++)

时间:2011-07-04 19:38:53

标签: c++ destructor

重新分配变量时,不会调用析构函数:

Object foo = Object(a,b);
foo = Object(c,d);

所以,析构函数只会在Object(c,d)范围的末尾被调用,这显然会导致问题。 现在,在这种特殊情况下,它并没有太多困扰我:它足以声明2个不同的对象:

Object foo1 = Object(a,b);
Object foo2 = Object(c,d);

这样就可以在最后调用两个对象的析构函数。

但是,有一种情况我必须重新分配变量,即在对象构造函数中,例如:

SuperObject(Point point1, Point point2) : delay_object_(DelayObject(0)) {
  double distance = distance(point1, point2);
  double delay = distance / speed;

  delay_object_ = DelayObject(delay);
}

事实上,DelayObject参数不容易计算(在这个例子中我也省略了一些其他段落),我想避免在初始化列表中这样做。

我以为我可以通过将对象放在堆中并显式调用析构函数来强制删除:

SuperObject(Point point1, Point point2) : p_delay_object_(new DelayObject(0)) {
  double distance = distance(point1, point2);
  double delay = distance / speed;

  delete p_delay_object_;
  p_delay_object_ = new DelayObject(delay);
}

但这对我来说真的很难看,因为我更喜欢仅在严格必要时使用动态分配。我错过了什么吗?

干杯!

4 个答案:

答案 0 :(得分:11)

“析构函数只会在Object(c,d)范围的末尾被调用”

假。 Object(c,d)是一个临时的,它的析构函数在创建它的全表达式的末尾被调用。在这种情况下,这是foo = Object(c,d);末尾的分号。 foo的析构函数在作用域末尾调用。

Object的赋值运算符应释放或重用foo已拥有的资源,并复制临时资源。不一定按顺序排列(参见copy-and-swap)。

编辑:回应评论。

Object foo = Object(a,b);

要么

  1. 使用任何双参数构造函数匹配(a,b)构建临时。
  2. foo是使用copy-constructor构造的,传递临时参数。
  3. 临时被毁。
    1. foo是使用任何双参数构造函数匹配(a,b)构建的。
    2. 实现可以自由执行 - “复制构造函数elision”允许这样做。

      foo = Object(c,d);
      
      1. 使用任何双参数构造函数匹配(c,d)构建临时。
      2. Object上调用类foo的赋值运算符,并传递临时参数。
      3. 临时被毁。
      4. 一段时间后,在范围的最后,foo被销毁。

        在C ++ 0x中,如果该类存在,则移动赋值将起作用。

答案 1 :(得分:8)

你应该重载赋值运算符,从概念上讲,它会复制构造现有对象并销毁旧的'this'。

class Object {
  ...
  Object& operator= (const Object& other) {
     if (this != &other) {
       // copy 'other' into 'this'.
     }
     return *this;
  }
  ...
};

然后foo = Object(c,d);行应该达到预期效果。

(同样提到@Steve Jessop,临时对象Object(c,d)也将在范围结束之后被破坏。)

请参阅What is The Rule of Three?

答案 2 :(得分:1)

是的,您忘记了可以重载赋值运算符。编译器默认提供的那个只是盲目地复制对象的所有字段,但是你可以自己提供你想做的任何事情,包括处理赋值对象目标的资源。

请注意,分配操作符很容易出错(忘记极端情况,异常安全......),我建议您阅读运算符重载常见问题解答at least this part,然后重定向{{3这几乎总是实现赋值运算符的唯一合理方法。


<强> 修改

另见@Steve Jessop的回答,它考虑了另一个根本的误解。

在你写的所有情况下

SomeClass sc = SomeClass(parameters);

您正在初始化一个新对象:您正在创建一个临时(SomeClass(parameters)),然后使用它的副本(通过复制构造函数)初始化sc;这是不必要的和低效的,在C ++中在堆栈上创建对象的语法只是

SomeClass sc(parameters);

答案 3 :(得分:0)

将DelayObject参数的计算委托给私有(可能是静态的)方法,并在初始化列表中构造DelayObject时使用它们。