以下代码运行正常。但是,当我在p=&b
中启用GetValue
时,代码失败“ Debug Assertion Failed”。为什么?
class A{
int *p;
public:
A(){p=nullptr;}
~A(){if(p!=nullptr)delete p;}
void GetValue(int b);
};
void A::GetValue(int b){
*p=b;
//p=&b; this will cause destructor to hang, why?
}
int main(void){
A B;
B.GetValue(5);
}
答案 0 :(得分:1)
首先,仅使用delete
分配的new
内存很重要。当前,您的类A
存储的指针p
并未使用new
进行分配,但是您像对待delete p
一样。结果是未定义的行为,这意味着不能保证您的程序行为正确,并且应该会出现非常奇怪的错误。
第二,在函数A::GetValue(int b);
中,参数b
是 temporary 变量。调用GetValue
时,将在调用堆栈上留出一些空间以传递b
的值,该值在函数的生存期内一直存在。但是在GetValue
返回后,b
不再存在。尽管C ++允许您将指向无效内存的指针存储在其中,但是您需要注意避免使用此类指针。
要使您的课程A
正常工作,需要进行一些修饰,但是我会尽力解释。尽管目前在一个简单的int*
成员可以做的地方存储int
指针似乎没有多大意义,但我将继续使用该指针来帮助您理解,并管理原始指针是一种学习练习。
大多数问题来自A::GetValue(int)
。在这里,您正在存储临时变量的地址,并且在需要new
-ed指针的上下文中。相反,您应该确保正确分配内存,而不要存储指向瞬态参数b
的指针:
A::GetValue(int b){
if (p == nullptr){
// if p is null, it needs to be allocated before being written to
p = new int(b); // initialize the memory at p to have value b
} else {
// otherwise, p has already been allocated, and its old value can be overwritten
*p = b;
}
}
编写以下代码时,还会出现另一个更细微的问题:
A a1, a2;
a1.GetValue(13);
a2 = a1;
这些行之后将发生的事情是p
的{{1}}成员将被删除两次,从而导致更多未定义的行为。罪魁祸首是automatically generated copy assignment operator,它只是按值将a1
从p
复制到a1
。要解决此问题,您需要编写自己的副本分配运算符和副本构造函数,如下所示。复制构造函数有点复杂,因为要处理很多不同的情况。
a2
Rule of Three中说明了这样做的重要性。
答案 1 :(得分:1)
长话短说,您的代码具有未定义的行为,因此一切都会发生。未定义的行为从这里开始:
void A::GetValue(int b){
*p=b;
//p=&b; this will cause destructor to hang, why?
}
p
在调用函数时为nullptr
,因此*p
是未定义的行为。其余代码甚至都没有关系。故事到此结束。
很抱歉,但是您对指针的使用却完全错误,以至于我们甚至无法确定代码的实际意图。如果不需要,请不要使用指针。如果不需要,请不要使用动态分配的内存。如果需要,可以使用std::vector
,std::string
,std::unique_ptr
或其他隐藏指针的标准类,这样您就不必编写自己的析构函数。避免直接使用new
和delete
。