为什么析构函数挂起

时间:2018-09-13 03:57:11

标签: c++ visual-c++

以下代码运行正常。但是,当我在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);
}

2 个答案:

答案 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,它只是按值将a1p复制到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::vectorstd::stringstd::unique_ptr或其他隐藏指针的标准类,这样您就不必编写自己的析构函数。避免直接使用newdelete