【问题标题】:Calling destructor of non-pointer member before pointer member在指针成员之前调用非指针成员的析构函数
【发布时间】:2015-12-05 16:52:54
【问题描述】:

考虑三个这样的类:

class A {
    int bar;
};

class B {
    A* a;
public:
    B(*A na)
    : a(na)
    {}

    ~B() {
        a->bar = 0;
    }
};

class Foo {
    A* a;
    B b;
public:
    Foo()
    : a(new A)
    , b(a)
    {}

    ~Foo() {
        delete a;
    }
};

创建Foo 的实例会导致Foo 带有指向A 的指针和带有相同指针的B

Foo的实例被删除时,指针a被删除,然后b的析构函数被调用,但~B试图访问a~Foo中被释放,这会导致分段错误。

有没有办法在运行~Foo的主体之前调用b的析构函数?

我知道我可以通过将b 设为指针或将a 设为非指针来解决此问题。如果A 是抽象的,则后者不起作用,我想知道是否可以不使b 成为指针。

PS:AB 都来自库,所以我无法更改它们的实现。

【问题讨论】:

  • 当您说“使a 成为指针”时,我预计缺少的单词(您忘记输入)是“不是”,但缺少的单词应该是“智能”。明确的答案是 a 应该是一个智能指针,所以它会以正确的顺序被删除。
  • 这并不能真正回答您的问题,但我建议只将 B 设为指针。您可以使用智能指针来完成您的要求,但我认为除非您有充分的理由,否则依赖基于成员顺序的破坏顺序是一种危险的做法,而且我认为这不是一个原因。最好只使它们成为指针并以正确的顺序破坏它们,并附上注释解释为什么必须按该顺序破坏它们。
  • @Gerald,设计显然必须取决于构造顺序。使用智能指针不会产生对序列的新依赖。它仅取决于破坏顺序与构造顺序相反,这是语言中内置的规则(除非您强制执行其他操作,就像 OP 通过使用非智能指针所做的那样)。
  • @JSF - 如果 ctor/dtor 的顺序像这样重要,我更愿意明确说明,而不是依赖于成员顺序。是的,该规则是内置在语言中的,但这并不意味着您想为了方便而依赖它。特别是在团队环境中,您只是在为这种设计找麻烦。即有一天可能会出现一个编码标准,成员应该按字母顺序声明,也许他们甚至使用一种工具来使代码达到标准,这会被打破,谁知道要花多长时间才能弄清楚发生了什么。 (去过那里。)
  • 如果他们真的被命名为 A 和 B 他会没事的,但不知何故我怀疑:)

标签: c++ pointers destructor


【解决方案1】:

遵循 RAII 原则。

Foo::a 更改为std::unique_ptr<A>。从~Foo 中删除delete

它现在将在~Foo 结束和b.~Bar() 之后被销毁。

请注意,成员是按照声明的顺序创建的,并以相反的顺序销毁。 (令人惊讶的是,初始化列表中的顺序不会改变创建顺序)。因此,如果您希望 ab 寿命更长,只需先声明它即可。

【讨论】:

    【解决方案2】:

    创建一个中间类。

     class PreFoo 
     {
       A* a:
        ...
     };
    
     class Foo : public PreFoo
     {
       B b;
       ...
     };
    

    【讨论】:

    • 您需要将 a 设为受保护或公开,我建议私有继承以匹配原始设计。
    【解决方案3】:

    编辑:纠正错误(感谢@Yakk)

    您需要将B 设为Foo 中的指针,以便您可以在析构函数中控制删除顺序,或者将A 设为非指针并将其定位在B 之前,以@987654325 的成员顺序@,所以它在B 之后被销毁,但这使得代码变得脆弱,因为成员声明的顺序现在很重要。在您的代码中对此进行注释。

    【讨论】:

    • 正如我在问题中所说,我知道这一点,但想知道是否可以不这样做。 (我编辑了问题以使这个限制更清楚,以防它不够清楚)
    • @Kritzefitz 你必须对Foo 做一些修改,唯一的问题是……
    • 当然我必须改变一些东西。但我不知道除了我排除的两个之外还有什么选择。也许有一些更优雅的解决方案,我不知道。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-17
    • 2018-04-14
    • 1970-01-01
    • 2018-03-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多