我有一个带有指向整数的指针的类。
然后是一个静态函数,它将返回该整数的值。
我注意到在调用静态函数时,每次都会为该对象调用析构函数。
我不明白为什么会发生这种情况。
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
我注意到两个狗对象都存在于不同的内存地址,但是int指针位于同一个地址。我相信这是因为在调用GetVal时会调用fido的析构函数,但我不知道为什么会发生这种行为。
答案 0 :(得分:9)
虽然“Fido”的析构函数确实被调用,但这不是原来的“Fido”,而是它的副本。您的GetVal(Dog d)
函数按值Dog
获取,这意味着“Fido”在传递到GetVal
之前被复制,然后在完成时销毁该副本。
通过Dog&
引用传递const
修复了此问题:
static int GetVal(const Dog& d){
return *(d.pVal);
}
注意:以上并不能解释为什么“Fido”获得21分。由于您没有定义复制构造函数或赋值运算符,因此编译器为您生成了一个简单的复制构造函数。结果,“Fido”副本中的pVal
指向与原始“Fido”中的pVal
相同的位置。一旦从Dog::GetVal(fido)
返回时副本被销毁,内存就有资格重用,并且原始“Fido”内的指针变得悬空。当您第二次调用Dog::GetVal(fido)
时,该函数会通过取消引用悬空指针来导致未定义的行为。第二个调用打印21的事实,你传递给“Rex”的构造函数的值,强烈暗示在销毁“Fido”的副本时释放的内存在构造“Rex”时会被立即重用。但是,没有要求C ++这样做。如果发生这种情况,您的代码会在运行结束时销毁“Rex”和“Fido”时第二次导致UB。