当变量仍然存在时调用 C++ 析构函数
Posted
技术标签:
【中文标题】当变量仍然存在时调用 C++ 析构函数【英文标题】:C++ Destructor being called when variable still alive 【发布时间】:2018-03-22 09:04:54 【问题描述】:我有一个带有指向整数的指针的类。
然后是一个静态函数,它将返回该整数的值。
我注意到在调用静态函数时,每次都会为该对象调用析构函数。
我不明白为什么会发生这种行为。
class Dog
public:
Dog(int val)
this->pVal = new int(val);
~Dog()
delete this->pVal;
static int GetVal(Dog d)
return *(d.pVal);
int *pVal;
;
这就是类。
这是我的测试驱动程序代码。
Dog fido(20);
std::cout << Dog::GetVal(fido); //20 and destructor for fido called
Dog rex(21);
std::cout << Dog::GetVal(fido); //21 but should be 20
std::cout << Dog::GetVal(rex); // should be 21
我注意到两个 dog 对象位于不同的内存地址,但 int 指针位于同一地址。我相信这是因为调用 GetVal 时调用了 fido 的析构函数,但我不知道为什么会发生这种行为。
【问题讨论】:
如果您使用 unique_ptr 而不是手动管理生命周期,您的编译器会显示您的错误(代码无法编译)。 仅仅因为另一个问题的答案适用于这个问题并不会使这个问题重复。这个问题是通过证明一个问题提出的; “重复”询问特定主题。除非你已经知道这个问题的代码有什么问题,否则你不会知道所谓的重复是相关的。 我同意 Darryl 的上述评论。投票重新开放。 【参考方案1】:虽然确实调用了“Fido”的析构函数,但这不是原来的“Fido”,而是它的副本。您的GetVal(Dog d)
函数按值获取Dog
,这意味着“Fido”在传递给GetVal
之前被复制,然后在完成时副本被销毁。
通过const
引用传递Dog&
可解决此问题:
static int GetVal(const Dog& d)
return *(d.pVal);
Demo.
注意:上面没有解释为什么你会因为“Fido”而得到 21。由于您没有定义复制构造函数或赋值运算符,编译器为您生成了一个简单的复制构造函数。结果,“Fido”副本中的pVal
指向与原始“Fido”中的pVal
相同的位置。一旦从Dog::GetVal(fido)
返回时副本被销毁,内存就可以重用,并且原始“Fido”内的指针变得悬空。当您第二次调用 Dog::GetVal(fido)
时,该函数会通过取消引用悬空指针来导致未定义的行为。第二次调用打印 21 的事实,即您传递给“Rex”构造函数的值,强烈表明在销毁“Fido”副本时释放的内存正在立即重用于构造“Rex”。但是,C++ 不需要这样做。如果发生这种情况,当“Rex”和“Fido”在运行结束时被销毁时,您的代码会第二次导致 UB。
【讨论】:
啊,非常感谢。我没有意识到已创建副本。 @mocode10 您应该遵循一些规则来防止出现此类问题。具体来说,五规则或零规则:github.com/isocpp/CppCoreGuidelines/blob/master/…、github.com/isocpp/CppCoreGuidelines/blob/master/… 解决这个问题的另一种方法是重载复制构造函数以创建一个新的 int 指针。以上是关于当变量仍然存在时调用 C++ 析构函数的主要内容,如果未能解决你的问题,请参考以下文章