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);