当包含指针成员的对象时,Segfault对堆栈上的对象进行破坏?

时间:2015-04-11 04:07:52

标签: c++ segmentation-fault stack heap destructor

以下情况似乎非常令人困惑(这不是一个正常工作的代码,只是一个非常简化的版本来说明方案,你明白了):

class A {
  private:
    B* mb;
  public:
    A(B *b):mb(b) {}
    ~A() {
      if(NULL != mb) { delete mb; }
    }
 }

 int main(int argc, char **argv) {
   B* b = new B();
   A* a = new A(b);
   delete A; //Everything is fine here
   B b;
   A* a = new A(&b);
   //This will segfault, because b is allocated on the stack?
   delete A; 
   B b;
   //This segfaults as well because when it goes out of scope
   //the program tries to delete b twice?
   A a(&b);
 }

如果我理解正确的话,这是否意味着当他们的类定义看起来像这样时,你不能再在堆栈上分配像A和B这样的对象?或者,我只是没有为A定义析构函数,然后A和B都可以在堆栈上分配---但这可能是坏的并且可能会导致内存泄漏? (如果有一天有人看到代码并决定新的A)。

我认为C ++相对于Java的主要优点是你可以避免使用新的并且总是处理堆栈上的对象以加快速度,但是在堆栈或堆上使用对象的这种不灵活性怎么样?

C ++中的交易是什么?那么应该采用以下两种方式中的哪一种?

  1. 如上所述定义A类,并且A和B都是新的,后来记得只删除A.

  2. 定义没有析构函数的A类,然后总是在堆栈上创建A和B并按值传递对象(但是有些情况下我不想要公共拷贝构造函数)。

    < / LI>

2 个答案:

答案 0 :(得分:3)

您在假设此段错误时是正确的,因为您正在删除在堆栈上分配的项目。您只能删除使用new分配的项目。此外,在同一层代码中分配和释放内存被认为是一种很好的做法。如果必须在代码中使用对象B,最好创建B的副本:

class A {
  private B* mb;
  public:
    A(B *b) {
      mb = new B(*b); // calls B's copy constructor
    }
    ~A() {
      if(NULL != mb) { delete mb; }
    }
}

答案 1 :(得分:2)

  

那么应该采用以下哪两种方式?

都不是。使用选项3:根本不要这样做。你是对的,C ++的一个优点就是你不需要newdelete,但是你编写了一大堆使用new和{{1}的代码}}

您尝试使用此delete解决了什么问题?毫无疑问,与A相比,有更好的方法来解决问题。