我有一个带有指向整数的指针的类。
然后是一个静态函数,它将返回该整数的值。
我注意到在调用静态函数时,每次都会为该对象调用析构函数。
我不明白为什么会发生这种行为。
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;
};
那就是类(class)。
这是我的测试驱动程序代码。
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
之前被复制,然后拷贝在完成后被销毁。
通过 Dog&
引用传递 const
解决了这个问题:
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/