从堆空间中删除对象

时间:2013-05-17 14:16:58

标签: c++ heap-memory

在main函数中,我使用new创建一个对象,不要删除它。我希望一旦进程退出就会清空堆空间。下面是一个示例代码,其中类A的对象是B类的成员变量B类还有一个多图作为成员变量。

    Class A
    {
    Public:
    A(); //have definition in cpp file
    ~A();//have definition in cpp file
    Private:
    Int a;
    };

    Class B{
    Private:
    Std::multimap<string,string> map_test;
    Public:
    A a;
    B(); //have definition inn cpp file
    ~B();//does not have any definition in cpp file
    };

    int main()
    {
      B *b = new B();
      /* code section where it fills some 1000 key value pairs in the multimap 
         for some purpose */
      return 0;

    }

我的理解:

  1. 即使我不删除这里的对象,它也不会产生任何问题,因为一旦进程退出就会清理堆空间。由于我的程序范围如上所述,并且没有其他人会重用这个那么不使用删除是好还是坏?你有什么建议吗?
  2. 它应调用对象的默认析构函数,然后调用隐式multimap析构函数。因此,不需要明确清除multimap。如果我错了,请纠正我。
  3. 在父类中它只是声明了析构函数并且没有任何定义。它会调用隐式析构函数还是忽略调用它?(没有理由不定义它,只是要求更好的理解。)
  4. 如果它在父类的情况下调用隐式析构函数,它是否应该调用此处定义的子类析构函数?
  5. 当使用new实例化父类对象时,它将在heap中创建。然后将存储该父对象的成员变量。例如,对象“a”是成员变量并通过查看声明这个成员对象,似乎它将在堆栈中创建。我只是在这里混淆了父对象及其成员子对象如何发生精确的内存创建。能帮助我理解这个吗?

4 个答案:

答案 0 :(得分:1)

  1. 是的,只要您的对象是在main中创建的。 但是,如果您想要改变它并且例如创建B的多个实例,或者在另一个类等中使用它等,那就是另一个故事。此外,像valgrind这样的内存检查工具会给你一个新的w / o删除的误报,你很想忽略它。但是,如果它成为习惯,你可能会忽略真正的内存泄漏。

  2. 正确,现在如果它是map<string, string*>那么你可能需要清理

  3. 它将调用默认析构函数

  4. 是的,

  5. 我想,你在问基类成员变量存储在哪里?它们也存储在堆上。它们位于内存中的派生类字段之前。

答案 1 :(得分:0)

你问了很多问题。

首先是它的最佳实践,即使进程退出并清除所有内存(如此),也可以清除内存。总是处理它......很容易使用shared_ptr ......

析构函数总是以正确的顺序调用,但是你的multimap是一个dangeorus,因为你应该清除multimap中的元素,就像你存储指针一样,它会导致严重的泄漏

答案 2 :(得分:0)

  1. 当进程退出时,大多数操作系统将清理进程的堆空间。如果有一堆嵌入式操作系统不是这样的话,我不会感到惊讶,加上它仍然是不好的做法,因为你确实有内存泄漏。
  2. 当你泄漏内存时,不会调用任何析构函数。也就是说,如果你没有实现析构函数并依赖编译器生成的默认析构函数,你也不应该声明它 - 实际上我很惊讶你没有收到链接器错误。是的,只要您观察容器对值语义的要求(即没有原始指针),multimap的默认析构函数将删除多图的内容。
  3. 这是不好的做法,作为程序员,您应该确保始终正确管理资源。此外,我没有看到堆分配b的任何原因,您只需在堆栈上创建对象,您就不必考虑资源管理。
  4. 如果确实声明它,则必须提供实现,因为析构函数的声明将隐式禁用编译器生成的析构函数。这就是为什么我在上面说过,我很惊讶你没有收到链接错误。
  5. 编译器将通过遍历层次结构并以相反的构造顺序调用析构函数来处理基类的销毁。
  6. 不,包含A和B的整个对象将在堆上构建 - 这就是为什么你可以将指向B的指针作为指向A的指针的别名,并与派生类交互,就像它是基类一样。

答案 3 :(得分:0)

事实:在C ++中没有本地(在表下)垃圾收集,尽管有很多东西可以强制执行某种垃圾收集。

因此,在您的代码中,您有内存泄漏。在您分配B的范围结束时,您分配的内存_不是 free'd

浏览您的问题列表:

  1. 不,如果您不删除指针,内存将不会被释放。关于此主题,您可以做一些事情:

    • 使用RAII idiom(资源获取是初始化),即使用对象来管理内存:
    • 使用智能指针:这些结构强制执行RAII(我认为最常见的是std::shared_ptrstd::unique_ptr)并确保他们负责的内存是正确免费的。
  2. 这取决于。如果您使用new运算符分配对象,然后将它们插入到地图中,但它们不会在其他任何地方引用,那么您应该手动删除地图的每个条目。它不适用于这种情况,因为地图类型不是指针。

  3. 该类甚至可以省略析构函数声明。如果省略它们,编译器将生成析构函数(但也包括复制赋值运算符,复制构造函数和默认构造函数)。

  4. 已编辑:这取决于,如果您声明了成员A a;,则不必显式删除它,当声明为成员的类调用析构函数时,将调用其析构函数。但如果它是你分配的指针(例如在构造函数中),那么你必须在析构函数中删除它。

  5. 对对象使用动态内存分配后,整个对象就在堆上,无论其成员如何声明。