当变量仍然存在时调用 C++ 析构函数
C++ Destructor being called when variable still alive
我有一个 class,它带有一个指向整数的指针。
然后是一个静态函数,它将 return 该整数的值。
我注意到在调用静态函数时每次都会为该对象调用析构函数。
我不明白为什么会出现这种行为。
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
之前被复制,然后副本在完成时被销毁。
通过 const
引用传递 Dog&
修复了这个问题:
static int GetVal(const Dog& d){
return *(d.pVal);
}
注:以上并没有解释为什么"Fido"得到21。由于您没有定义复制构造函数或赋值运算符,因此编译器会为您生成一个普通的复制构造函数。结果,"Fido" 副本中的 pVal
指向与原始 "Fido" 中的 pVal
相同的位置。一旦副本在 Dog::GetVal(fido)
return 时被销毁,内存就可以重新使用,并且原始 "Fido" 中的指针变得悬空。当您第二次调用 Dog::GetVal(fido)
时,该函数通过取消引用悬空指针而导致未定义的行为。事实上,第二次调用打印 21,即您传递给 "Rex" 的构造函数的值,这强烈表明销毁 "Fido" 的副本时释放的内存将立即在构造 [=38] 时重新使用=].但是,C++ 不需要这样做。如果发生这种情况,当 "Rex" 和 "Fido" 在 运行.
结束时被销毁时,您的代码将第二次导致 UB
我有一个 class,它带有一个指向整数的指针。
然后是一个静态函数,它将 return 该整数的值。
我注意到在调用静态函数时每次都会为该对象调用析构函数。
我不明白为什么会出现这种行为。
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
之前被复制,然后副本在完成时被销毁。
通过 const
引用传递 Dog&
修复了这个问题:
static int GetVal(const Dog& d){
return *(d.pVal);
}
注:以上并没有解释为什么"Fido"得到21。由于您没有定义复制构造函数或赋值运算符,因此编译器会为您生成一个普通的复制构造函数。结果,"Fido" 副本中的 pVal
指向与原始 "Fido" 中的 pVal
相同的位置。一旦副本在 Dog::GetVal(fido)
return 时被销毁,内存就可以重新使用,并且原始 "Fido" 中的指针变得悬空。当您第二次调用 Dog::GetVal(fido)
时,该函数通过取消引用悬空指针而导致未定义的行为。事实上,第二次调用打印 21,即您传递给 "Rex" 的构造函数的值,这强烈表明销毁 "Fido" 的副本时释放的内存将立即在构造 [=38] 时重新使用=].但是,C++ 不需要这样做。如果发生这种情况,当 "Rex" 和 "Fido" 在 运行.