你在C ++中的析构函数中调用delete吗?

时间:2013-11-06 01:15:34

标签: c++ pointers destructor

假设你有一个这样的课程

  class Level
  {
    public:

     Level(std::string);
     ~Level();

    private:
     Bitmap* map;  
  }

在课堂上你有这个

Level::Level(std::string)
{
  map = new Bitmap(path);
}

想知道你能打电话吗

Level::~Level()
{
 delete map;
}

因为我担心课程是否超出范围而且我没有删除地图。然后,这不会导致内存泄漏。我是否必须手动呼叫才能删除地图。如果我在我的程序中的构造函数中调用delete,则会崩溃。

就像我可以添加一个方法到Level调用说破坏地图我删除地图。但是,想知道为什么我不能将删除添加到析构函数中。

6 个答案:

答案 0 :(得分:4)

Level对象超出范围时,将调用其析构函数,因此释放内存非常有用,因为不再需要该内存。您还可以使用unique_ptr,从而自动执行内存释放。

答案 1 :(得分:3)

答案已经指出,当对象超出范围时,您可以信任您的析构函数被调用。我不会重申这一点。我只是想指出,不需要使用Bitmap分配new(除非您使用的是自定义内存分配器,但这不是这种情况)。您可以使用初始化列表构建它:

class Level
{
  public:
    Level(std::string);

  private:
     Bitmap map;  
};

Level::Level(std::string)
    : map(path)
{
}

现在它具有自动范围,您不必担心您的析构函数。

答案 2 :(得分:2)

这就是析构者所代表的原因。当对象超出范围(驻留在堆栈对象上的内存)或调用delete时(对于动态分配的对象),将显式调用析构函数,以便释放对象保留的内存。如果要在销毁时释放成员对象内存,可以使用delete(或delete[]用于数组)调用每个对象的析构函数。最好使用智能指针,以避免无意的内存泄漏,并确保在所有情况下都能正确释放内存,因为它们使用RAII概念(RAII and smart pointers in C++)。

答案 3 :(得分:2)

这基本上是正确的。

然而:

  • 如果您以这种方式管理内存,则需要确保创建复制构造函数和赋值运算符。 (这就是你的崩溃所在。)

  • 另一种选择,最好的方法,是使用RAII并且不存储原始指针而是存储范围或自动指针。甚至只是一个直接封装的对象!那么您根本不需要delete

答案 4 :(得分:0)

  

因为我担心课程是否超出范围而且我没有删除地图。然后,这不会导致内存泄漏。

你是对的 - 你应该delete map完全按照你的代码做。但是,您还应该使您的对象不可复制(从boost或C ++ 11不可复制的基类派生,或者添加operator=复制赋值和复制构造函数的私有声明(没有定义/实现)。否则,如果您(故意或偶然或偶然地 - 例如,当您将对象存储在有时会复制它的容器中时,例如std::vector)复制您的对象,那么第一个被解构的副本将delete { {1}},尝试使用它的任何其他副本都可能会崩溃,并且任何其他副本的析构函数也会尝试map它也会有未定义的行为。

  

我是否必须手动调用以删除地图。

是的,在您的代码中。

更好的选择是使用智能指针,其自己的析构函数将删除指向的对象。

  

如果我在程序的构造函数中调用delete,那么我会崩溃。

好吧,如果你在delete之后调用delete,那么构造函数不会崩溃,但是在构造函数返回后你不会有new个对象使用,并且如果你然后在析构函数中再次尝试map,你会得到未定义的行为,这可能表现为崩溃。

如果您希望有时{@ 1}}地图早于析构函数,您可以将指针设置为delete,以便将来delete无法安全地执行任何操作。然后,您应该在尝试使用NULL之前检查NULL。

  

就像我可以添加一个方法到Level调用说破坏地图我删除地图。但是,想知道为什么我不能将删除添加到析构函数中。

如上所述,您可以拥有delete,但必须与析构函数协调。

如果没有令人信服的理由不这样做,最好制作map成员数据,而不是通过引用存储它。当指针有用时,如果可能的话,使用智能指针。如果要实现明确的手动内存管理,请注意上述问题。

答案 5 :(得分:-3)

这是一种不寻常的方式。通常,对象的生命周期由对象之外的因素决定。

但实际上MFC曾经(仍然如此?)在Window被销毁时就是这么做的。 (响应WM_NCDESTROY,我相信。)这可以确保在窗口消失后没有Window实例泄漏内存。

所以我想说它在某些情况下是有效的。你可以称之为自杀!