【问题标题】:C++ Destructor crashing on a call to deleteC++ 析构函数在调用删除时崩溃
【发布时间】:2015-02-10 23:10:43
【问题描述】:

我有一个非常奇怪且可能很明显的问题,但我似乎找不到错误。我有一个类对象,它包含一个指向另一个类对象的指针,当第一个的解构器被调用时,它会尝试删除它的指针,但会导致段错误而没有进入第二个的解构器。

具体来说,我有一个优化器类的实例:

class Optimizer {
public:
    Optimizer();
    ~Optimizer();

   //Lot's of public methods and such

private:
    PredictionRenderer *_predictionRenderer;

    //Lot's of member variables

};

Optimizer::~Optimizer() {
    std::cout<<"optimizer destructor:"<<_predictionRenderer->getWidth()<<std::endl;
    delete _predictionRenderer; //THIS LINE CRASHES AND NEVER MAKES IT INTO THE PREDICTION RENDERER DECONSTRUCTOR
    //other calls
}

(这是一个大项目,所以为了简洁起见,我删除了所有额外的方法/变量)。

Optimizer 有一个指向 PredictionRenderer 对象的指针,_predictionRenderer。该指针在调用构造函数期间被初始化。该指针是私有的,我检查并确保它不能“退出”(也就是说,此优化器对象之外的任何人都无法获取此指针。它永远不会被任何优化器的方法返回,也永远不会通过优化器方法传递给任何方法)。

当尝试删除 Optimizer 对象时,我的程序在 delete _predictionRenderer 行出现了段错误。执行永远不会进入 PredictionRenderer 解构器。我在delete调用之前的print语句中添加了验证指针不是NULL或者已经被删除,并且调用PredictionRenderer的getWidth方法成功返回,说明一定是一个有效的指针(是否可以调用已删除的对象?)。此外,打印语句只打印一次,所以我很确定优化器对象没有被复制和删除两次。最后,PredictionRenderer 的解构器永远不会被调用,也不会被 delete 或其他任何地方调用。

我不知道是什么原因造成的。有没有人知道发生了什么?

编辑:正如我在 cmets 中提到的,这个代码库很大。我很抱歉没有展示太多,但我无法真正展示所有内容,因为空间不足。这是我正在使用的其他人的代码,据我所知,他实际上从未破坏过这个对象,他只是让它在程序退出时被释放。我也可以这样做,但这似乎是一种黑客行为,不是做生意的好方法。

【问题讨论】:

  • (This is a big project, so for brevity I removed all the extra methods/variables). 不。重要的是不要遗漏类的内部信息。原因是我们需要看看你的班级是否遵循“3规则”。 stackoverflow.com/questions/4172722/what-is-the-rule-of-three
  • 最有可能的是,发生的事情是您正在双重删除,可能是由于不遵循 3 (5) 的规则,并且在没有重新分配的情况下复制指针,所以当您销毁 COPY对象,一切顺利,但是当你去销毁原来的对象时,你又删除了同一个对象。但可能还有很多其他事情,例如覆盖一些缓冲区并因此破坏堆。
  • But the only time this would be a problem is if Optimizer gets copied (which it might), 然后停在那里——程序将表现出未定义的行为,无论你多么想合理化为什么没有错误。
  • @Rae_III BTW,正确的术语是destructor,而不是deconstructor。此外,您的默认构造函数是否将您的指针初始化为(至少)NULL
  • 在类中声明一个 private copy-ctor 声明 Optimizer(const Optimizer&amp;);。无需实施(事实上,我们需要你来实施)。同样对于赋值运算符Optimizer&amp; operator =(const Optimizer&amp;);。两者都应声明为private: 且未实现。然后从头开始重新编译。如果它在任何地方破坏了编译,你就会知道没有制作价值副本是大错特错。

标签: c++ pointers segmentation-fault delete-operator


【解决方案1】:

你确定还有_predictionRenderer 可以删除吗?你应该先检查一下。

if (_predictionRenderer)
    delete _predictionRenderer;

如果你试图删除一个从未分配内存的指针,你的程序将会崩溃。

【讨论】:

  • 是的,这是我的第一个想法,但我知道它至少得到了分配,因为分配是在优化器构造函数中完成的。此外,正如您在上面的解构器中看到的,在删除调用之前,我调用了 predictionRenderer 的 getWidth 方法,该方法返回正确的值,因此它至少被初始化了。
  • delete 在一个空对象上很好(所以添加一个额外的 if 只会导致代码膨胀,当它在同一个可执行文件中完成数千次时[取决于编译器没有检测到它并删除它,在在这种情况下,每次阅读它只是浪费程序员的时间]。如果它未初始化、已被删除或以其他方式“不是一个好的和有效的指针”,则 if 并没有太大帮助。
  • @LawrenceAiello:那是什么非常古老的编译器/C++ 库。据我所知,至少从 1998 年标准开始,删除 0 指针是安全的。
  • @MatsPetersson 它可能咬了他,因为他从未将其初始化为 NULLnullptr 或构造函数初始化列表中的有效值。
  • if 测试比没用还糟糕。如果它是一个空指针,那么它没有区别,因为删除一个空指针是安全的;如果不是空指针,则通过测试
【解决方案2】:

您发布的代码行没有错。 我建议在初始化后立即交叉检查_predictionRenderer ptr 的值,并将其与您在Optimizer::~Optimizer() 中看到的值进行比较。他们应该是一样的,如果不是你在外面有问题。可能是您的容器对象已损坏。

【讨论】:

    猜你喜欢
    • 2023-03-15
    • 2018-01-03
    • 2012-03-13
    • 2016-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-29
    • 2012-04-06
    相关资源
    最近更新 更多