在析构函数中删除指针时崩溃 我碰到了我对C++中指针的缺乏理解。我编写了一个名为Skymap的类,其定义如下: class Skymap { public: Skymap(); ~Skymap(); void DrawAitoffSkymap(); private: TCanvas mCanvas; TBox* mSkymapBorderBox; };

在析构函数中删除指针时崩溃 我碰到了我对C++中指针的缺乏理解。我编写了一个名为Skymap的类,其定义如下: class Skymap { public: Skymap(); ~Skymap(); void DrawAitoffSkymap(); private: TCanvas mCanvas; TBox* mSkymapBorderBox; };,c++,pointers,destructor,C++,Pointers,Destructor,其功能定义如下: #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

其功能定义如下:

#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
}

(我使用的是根绘图包,但我认为这只是一个普通的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对象中的指针似乎有问题,但我看不出是什么问题

TBox* mSkymapBorderBox=new TBox(-200,-100,200,100);
在这里,您将内存分配给一个局部变量,而不是成员变量。而且,由于您没有为成员变量分配内存,因此对其调用
delete
将调用未定义的行为,这将导致本例中的崩溃

你应该做的是:

mSkymapBorderBox=new TBox(-200,-100,200,100);
现在为成员变量分配内存。这就是为什么局部变量的命名应该不同于成员变量的原因之一。命名约定有助于避免此类错误


作为旁注,或者说是一个非常重要的注释,因为您的类管理资源,考虑适当地实现复制语义和析构函数:这个规则被普遍称为。或者使用一些智能指针,例如

std::shared_ptr
std::unique_ptr
或任何适合您的场景的指针。

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

  • 如果有人创建了一个SkyMap,但从未使用它调用DrawAitoffSkymap,那么您将获得未定义的行为(因为mSkymapBorderBox从未初始化,所以它将具有一个随机值,然后您将其删除)
  • 如果有人使用给定的SkyMap多次调用DrawAitoffSkymap,那么您将出现内存泄漏
  • 要修复:

    (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(...);
       ...
    }
    

    TBox*mSkymapBorderBox=新的TBox(-200,-100200100)
    您正在创建一个新的
    TBox*
    指针,它不是数据成员

    在同一逻辑单元/范围内实施新的
    后,考虑正确实施
    删除

    TBox* mSkymapBorderBox=new TBox(-200,-100,200,100);
    
    声明此时,将创建类TBox的对象。当你退出时 此时DrawAitoffSkymap将丢失此分配内存的引用

    在调用析构函数时,它会释放一些垃圾内存

    要避免这种情况,请使用此
    mSkymapBorderBox=new-TBox(-200,-100200100)

    而不是
    TBox*mSkymapBorderBox=new-TBox(-200,-100200100)

    哦,哇,非常感谢!有点尴尬,但我很感激你的快速回复!即使是最有经验的开发人员也会犯这样的错误。问问题从不令人尴尬;-)您的欢迎但如果您不检查是否已经分配了
    mSkymapBorderBox
    (加上初始化为
    NULL
    ),调用DrawAitoffSkymap的额外时间将导致内存泄漏。这不是问题的原因,但在管理资源时请始终记住。更好的是,不要自己管理资源-使用、容器和其他RAII类。如果在构造函数中没有分配,那么您应该始终将指针设置为
    NULL
    。非常感谢这一点-我以前没有太多处理指针,所以我需要养成在代码中添加此类检查等的习惯。我会记住你的建议!