1

在主函数中,我使用 new 创建了一个对象并且不删除它。我希望进程退出后会清除堆空间。下面是示例代码,其中 A 类的对象是 B 类的成员变量。 B 类也有一个 multimap 作为成员变量。

    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. 它应该调用对象的默认析构函数,然后调用隐式多映射析构函数。所以它不需要明确清除多图。如果我错了,请纠正我。
  3. 在父类中它只是声明了析构函数,并没有任何定义。那么它会调用隐式析构函数还是忽略调用它?(没有理由不定义它,只是要求更好的理解。)
  4. 如果它在父类的情况下调用隐式析构函数,是否应该调用此处定义的子类析构函数?
  5. 由于父类对象是使用new实例化的,它将在堆中创建。然后将存储该父对象的成员变量的确切位置。例如对象“a”是一个成员变量,并通过查看该成员的声明对象,似乎它会在堆栈中创建。我在这里很困惑父对象及其成员子对象的确切内存创建是如何发生的。你能帮我理解这个吗?
4

4 回答 4

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

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

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

  4. 是的,它会的

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

于 2013-05-17T14:29:37.643 回答
0

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

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

浏览您的问题列表:

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

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

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

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

  5. 一旦你为一个对象使用动态内存分配,整个对象就在堆上,不管他的成员是如何声明的。

于 2013-05-17T14:38:52.817 回答
0

你问了很多问题。

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

析构函数总是以正确的顺序被调用,但是你的多重映射是危险的,因为你应该清除多重映射中的元素,就像你存储指针一样,它可能会导致严重的泄漏

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