当变量仍然存在时调用 C++ 析构函数

标签 c++ destructor

我有一个带有指向整数的指针的类。

然后是一个静态函数,它将返回该整数的值。

我注意到在调用静态函数时每次都会为该对象调用析构函数。

我不明白为什么会发生这种行为。

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 的析构函数,但我不知道为什么会出现这种行为。

最佳答案

虽然确实调用了“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。

关于当变量仍然存在时调用 C++ 析构函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46675507/

相关文章:

c++ - Doxygen:使用 C++ 和 VHDL 的项目的无缝文档

java - 如何通过套接字 C++ 服务器/Java 客户端发送 int

c++ - 显式删除析构函数而不调用 delete

C++ Qt 基类虚析构函数

c++ - 使用 boost 图进行图像分割

c++ - Direct3D 11 深度缓冲区导致黑屏

c++ - 获得更好的 iostream 错误消息

C++ SDL_FreeSurface 在析构函数中崩溃

c++ - 从 C++ 析构函数调用自定义免费 C 例程?

c++ - 可以使用类的析构函数内部函数来重置值吗?