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

moc*_*e10 3 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;
};
Run Code Online (Sandbox Code Playgroud)

那是班级.

这是我的测试驱动程序代码.

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
Run Code Online (Sandbox Code Playgroud)

我注意到两个狗对象都存在于不同的内存地址,但是int指针位于同一个地址.我相信这是因为调用GetVal时会调用fido的析构函数,但我不知道为什么会出现这种行为.

das*_*ght 9

虽然"Fido"的析构函数确实被称为,但这不是最初的"Fido",而是它的副本.您的GetVal(Dog d)函数Dog按值获取,这意味着"Fido"在传递之前被复制GetVal,然后复制在完成时被销毁.

Dog&通过const引用传递修复此问题:

static int GetVal(const Dog& d){
    return *(d.pVal);
}
Run Code Online (Sandbox Code Playgroud)

演示.

注意:以上内容并不能解释为什么"Fido"获得21分.由于您没有定义复制构造函数或赋值运算符,因此编译器为您生成了一个简单的复制构造函数.结果,pVal"Fido"的副本指向pVal与原始"Fido" 相同的位置.一旦从Dog::GetVal(fido)内存返回时副本被破坏就有资格重用,并且原始"Fido"内的指针变得悬空.当您Dog::GetVal(fido)第二次调用时,该函数通过取消引用悬空指针来导致未定义的行为.第二个调用打印21的事实,你传递给"Rex"的构造函数的值,强烈暗示在销毁"Fido"的副本时释放的内存在构造"Rex"时会被立即重用.但是,没有要求C++这样做.如果发生这种情况,您的代码会在运行结束时销毁"Rex"和"Fido"时第二次导致UB.