当对象包含指针成员时,堆栈上对象破坏的段错误?

Segfault on object destruction on the stack when object containing pointer member?

下面的场景看起来很令人费解(这不是一个工作代码,只是一个非常简化的版本来说明这个场景,你明白了):

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 等对象的 class 定义如下所示时,您永远不能再在堆栈上分配此类对象?或者,我只是简单地不为 A 定义析构函数,然后 A 和 B 都可以分配到堆栈上 --- 但这可能很糟糕并且可能会导致内存泄漏? (如果有一天其他人看了代码并决定使用新的 A)。

我认为 C++ 相对于 Java 的主要优势是你可以避免 new 并始终处理堆栈上的对象以加快速度,但是在堆栈或堆上使用对象的这种不灵活性又如何呢,喜欢吗?

C++ 有什么问题?那么下面两种方式应该走哪一种呢?

  1. 如上定义classA,A和B总是new,以后记得只删除A。

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

你假设这个段错误是正确的,因为你正在删除一个在堆栈上分配的项目。您只能删除分配给新的项目。此外,在同一代码层内分配和释放内存被认为是一种很好的做法。如果您必须在代码中使用对象 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; }
    }
}

Which of the following two ways should one go then?

都没有。使用选项 3:根本不要这样做。你是对的,C++ 的一个优点是你不需要 newdelete,但是你写了一大堆使用 newdelete 的代码.

你想用这个 A 解决什么问题?毫无疑问,有比 A.

更好的方法来解决问题