在析构函数中删除指针时崩溃

时间:2012-02-22 18:34:00

标签: c++ pointers destructor

我遇到了对C ++中指针缺乏深刻理解的问题。我写了一个名为Skymap的类,其定义如下:

class Skymap {
 public:
  Skymap();
  ~Skymap();
  void DrawAitoffSkymap();
 private:
  TCanvas mCanvas;

  TBox* mSkymapBorderBox;
};

将函数定义为:

#include "Skymap.h"

Skymap::Skymap()
{
  mCanvas.SetCanvasSize(1200,800);
  mMarkerType=1;
}

Skymap::~Skymap()
{
  delete mSkymapBorderBox;
}

void Skymap::DrawAitoffSkymap()
{
  TBox* mSkymapBorderBox=new TBox(-200,-100,200,100);
  //Use the mSkymapBorderBox pointer for a while
}

(我正在使用ROOT绘图包,但我认为这只是一个普通的C ++问题。)

现在,以下程序在到达skymap2的析构函数时会崩溃:

int main(){
  Skymap skymap1;
  Skymap skymap2;
  skymap1.DrawAitoffSkymap();
  skymap2.DrawAitoffSkymap();
  return(0);
}

但是,以下内容不会崩溃:

int main(){
  Skymap skymap1;
  skymap1.DrawAitoffSkymap();
  return(0);
}

另外,如果我在构造函数中将指针mSkymapBorderBox初始化为NULL,那么在执行第一个程序(使用2个Skymap对象)后,我不会再遇到崩溃。

任何人都可以解释一下其根本原因是什么?它似乎是第二个Skymap对象中指针的问题,但我看不出它是什么。

4 个答案:

答案 0 :(得分:16)

TBox* mSkymapBorderBox=new TBox(-200,-100,200,100);

这里你要将内存分配给局部变量,而不是成员变量。由于您没有为成员变量分配内存,因此在其上调用delete将调用未定义的行为,这会导致您的情况崩溃。

你应该做的是:

mSkymapBorderBox=new TBox(-200,-100,200,100);

现在为成员变量分配内存。这是为什么局部变量的名称与成员变量不同的原因之一。命名约定有助于避免此类错误。

作为旁注,或者更重要的是,由于您的班级管理资源,请考虑正确实现复制语义和析构函数:此规则通常称为the-rule-of-three。或者使用一些智能指针,例如std::shared_ptrstd::unique_ptr或适用于您的方案的任何内容。

答案 1 :(得分:7)

Nawaz的回答是正确的。但除此之外,您的代码有几个可能的问题:

  1. 如果有人创建SkyMap并且从不使用它调用DrawAitoffSkymap,那么你将得到未定义的行为(因为mSkymapBorderBox永远不会被初始化,它会有一个随机值,然后你可以删除它。)
  2. 如果有人使用给定的SkyMap多次调用DrawAitoffSkymap,那么你将会出现内存泄漏。
  3. 修复:

    (1)在构造函数中将mSkymapBorderBox初始化为零。

    (2)决定如果多次调用DrawAitoffSkymap应该做什么。如果它应该重用旧的mSkymapBorderBox,那么你会想要说:

    void Skymap::DrawAitoffSkymap() {
       if (!mSkymapBorderBox) mSkymapBorderBox = new TBox(...);
       ...
    }
    

    另一方面,如果每次都要创建一个新的TBox,那么你想要:

    void Skymap::DrawAitoffSkymap() {
       delete mSkymapBorderBox; // note: does nothing if mSkymapBorderBox == 0
       mSkymapBorderBox = new TBox(...);
       ...
    }
    

答案 2 :(得分:0)

TBox* mSkymapBorderBox=new TBox(-200,-100,200,100);您正在创建一个新的TBox*指针,该指针不是数据成员。

考虑在同一逻辑单元/范围内实施delete后正确实施new ...

答案 3 :(得分:0)

TBox* mSkymapBorderBox=new TBox(-200,-100,200,100);

当你声明这个时,创建一个TBox类的对象。当你退出 此时DrawAitoffSkymap会丢失此分配内存的引用。

当析构函数被及时调用时,它会释放一些垃圾内存。

为避免这种情况,请使用此 mSkymapBorderBox=new TBox(-200,-100,200,100);
 而不是TBox* mSkymapBorderBox=new TBox(-200,-100,200,100);