Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/amazon-web-services/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 重新分配变量时,不会调用析构函数。。(C+;+;)_C++_Destructor - Fatal编程技术网

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

C++ 重新分配变量时,不会调用析构函数。。(C+;+;),c++,destructor,C++,Destructor,重新分配变量时,不会调用析构函数: Object foo = Object(a,b); foo = Object(c,d); 因此,析构函数将只在对象(c,d)的作用域末尾调用,这显然会导致问题。 现在,在这个特定的例子中,我并不觉得太麻烦:声明两个不同的对象就足够了: Object foo1 = Object(a,b); Object foo2 = Object(c,d); 这样,两个对象的析构函数都将在最后被调用 但是,在某些情况下,我需要重新分配变量,即在对象构造函数中,例如: Sup

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

Object foo = Object(a,b);
foo = Object(c,d);
因此,析构函数将只在对象(c,d)的作用域末尾调用,这显然会导致问题。 现在,在这个特定的例子中,我并不觉得太麻烦:声明两个不同的对象就足够了:

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);
}
但这在我看来真的很难看,因为我更喜欢只在严格必要时使用动态分配。我错过什么了吗


干杯

您应该重载赋值运算符,从概念上讲,赋值运算符将复制构造现有对象并销毁旧的“this”

class Object {
  ...
  Object& operator= (const Object& other) {
     if (this != &other) {
       // copy 'other' into 'this'.
     }
     return *this;
  }
  ...
};
然后
foo=Object(c,d)行应该执行您期望的操作

(同样如上所述,临时对象
对象(c,d)
也将在作用域结束后销毁。)


请参阅。

是的,您忘记了可以重载赋值运算符。编译器默认提供的方法只是盲目地复制对象的所有字段,但您可以提供自己的字段来执行任何操作,包括处理赋值对象目标的资源

请注意,赋值运算符很容易出错(忘记拐角情况、异常安全等),我建议您阅读我们的运算符重载常见问题解答,它反过来重定向,这几乎总是实现赋值运算符的唯一合理方法


编辑

此外,请参见@Steve Jessop的回答,这考虑了另一个基本误解

在你写作的所有情况下

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

SomeClass sc(parameters);
析构函数将仅在对象(c,d)的作用域结束时调用

Object(c,d)
是一个临时对象,在创建它的完整表达式的末尾调用它的析构函数。在本例中,这是
foo=Object(c,d)末尾的分号。在作用域末尾调用
foo
的析构函数

Object
的赋值运算符应释放或重新使用
foo
已持有的资源,并复制临时用户持有的资源。不一定按该顺序(请参见复制和交换)

编辑:回应评论

Object foo = Object(a,b);
或者

  • 使用与
    (A,b)
    匹配的任何两个参数构造函数来构造临时变量
  • foo
    使用复制构造函数构造,并将临时作为参数传递
  • 临时文件被销毁
  • foo
    是使用与
    (a,b)
    匹配的任何两个参数构造函数构造的
  • 实现可以自由地执行这两种操作—这是“复制构造函数省略”所允许的

  • 使用与
    (c,d)
    匹配的任何两个参数构造函数来构造临时变量
  • 对象
    的赋值运算符在
    foo
    上调用,将临时作为参数传递
  • 临时文件被销毁
  • 一段时间后,在作用域的末尾,
    foo
    被销毁


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

    将DelayObject参数的计算委托给私有(可能是静态)方法,并在初始值设定项列表中构造DelayObject时使用这些方法。

    您没有键入对象foo(a,b)
    有什么原因吗?然后再把foo的值改成c和d?为什么您认为正确的方法是创建并复制整个对象?我不认为你在考虑堆栈语义。谢谢凯特。没什么理由:自从我上次用C++以来,已经有很长时间了。史提夫:谢谢。将注释抽象为“将“其他”复制到“此”中:)。顺便说一句,对于那些对复制和交换感兴趣的人来说:。只需对此说不,当对象的动态类型不等于其静态类型时,它将杀死你们。另外,如何在从Object派生的类中处理运算符=呢?使用createtemporary和swap习惯用法。也许值得一提的是,当您发现必须编写自己的析构函数,从而提供复制和赋值构造函数时,您应该三思。通常,有一种更好的方法可以使用现代库工具完全避免这种情况。正如Stephan T Lavavej所说,“不要编写自己的复制构造函数,那是邪恶的”…@Tomek:我不明白你的意思。创建临时和交换以及子类型是两个不同的问题。您需要在派生类中使用或不使用该习惯用法再次重写
    运算符=
    。不能通过赋值将堆栈上的
    对象
    更改为
    派生的
    。@Enzo:最好使用智能数据成员设计类,这样就不必提供自定义的副本构造函数。但是你必须知道如何设计你的类(而且这可能并不总是可能的)。复制省略处理了一个甚至是半体面的编译器中的低效问题,这两种形式变得相当。我稍微喜欢带有
    =
    的版本,因为它从来都不是最麻烦的解析,但这是一个风格问题。当然,如果探查器说复制删除失败,那么
    foo = Object(c,d);