【问题标题】:Preventing memory leaks in polymorphic classes防止多态类中的内存泄漏
【发布时间】:2018-04-13 06:59:38
【问题描述】:

在下面的练习中,我创建了一个基类和几个派生类之间的多态关系:

#include <iostream>
using namespace std;

class Panthera
{
public:
    virtual void roar() = 0;
    virtual ~Panthera() {}
};

class Lion : public Panthera
{
public:
    void roar() { cout << "roaring like a lion... " << endl; }
};

class Tiger : public Panthera
{
public:
    void roar() { cout << "roaring like a tiger..." << endl; }
};

class Jaguar : public Panthera
{
public:
    void roar() { cout << "roaring like a jaguar... " << endl; }
};

class Leopard : public Panthera
{
public:
    void roar() { cout << "roaring like a leopard... " << endl; }
};

void speak(Panthera *object)
{
    object->roar();

    delete object; // this is meant to prevent memory leak

    cout << "deleting pointer... " << endl;
}

int main()
{

    Lion lion;
    Tiger tiger;
    Jaguar jaguar;
    Leopard leopard;

    speak(&lion);
    speak(&tiger);
    speak(&jaguar);
    speak(&leopard);

    cout << "program ending... " << endl;

}

我已将基类析构函数设置为 virtual 并删除函数“speak”中的指针以防止内存泄漏,虽然代码在没有任何警告或错误的情况下编译和运行,但我从内存泄漏中得到以下结果检测器:

Error #1: INVALID HEAP ARGUMENT to free 0x0028ff2c
# 0 replace_free               [d:\drmemory_package\com...
# 1 Lion::~Lion                [../src/bigCats.cpp:11]
# 2 speak                      [../src/bigCats.cpp:39]
# 3 main                       [../src/bigCats.cpp:52]
Note: @0:00:01.466 in thread 7936

Error #2: INVALID HEAP ARGUMENT to free 0x0028ff28
# 0 replace_free                [d:\drmemory_package\com...
# 1 Tiger::~Tiger               [../src/bigCats.cpp:17]
# 2 speak                       [../src/bigCats.cpp:39]
# 3 main                        [../src/bigCats.cpp:53]
Note: @0:00:01.482 in thread 7936

Error #3: INVALID HEAP ARGUMENT to free 0x0028ff24
# 0 replace_free                  [d:\drmemory_package\com...
# 1 Jaguar::~Jaguar               [../src/bigCats.cpp:23]
# 2 speak                         [../src/bigCats.cpp:39]
# 3 main                          [../src/bigCats.cpp:54]
Note: @0:00:01.497 in thread 7936

Error #4: INVALID HEAP ARGUMENT to free 0x0028ff20
# 0 replace_free                    [d:\drmemory_package\com...
# 1 Leopard::~Leopard               [../src/bigCats.cpp:29]
# 2 speak                           [../src/bigCats.cpp:39]
# 3 main                            [../src/bigCats.cpp:55]
Note: @0:00:01.529 in thread 7936

我还注意到该程序偶尔会随机崩溃,尽管它似乎大部分时间都在工作。奇怪的是,当我去掉“speak”函数中的“delete object”命令时,这些来自内存泄漏检测器的错误完全消失了。

有人可以向我解释一下这里发生了什么吗?我的教科书理解告诉我,我需要删除指向基类的指针以防止内存错误并避免不可预知的程序行为,但我似乎遇到了完全相反的情况。

【问题讨论】:

  • 只有通过new获得的delete指针。您的对象在堆栈上,因此您无需执行任何操作。

标签: c++ memory-management memory-leaks polymorphism


【解决方案1】:

在 C++ 中,您必须仔细管理所有对象的生命周期。

delete x 仅在指向由new 创建的对象的指针上有效。

您在自动存储中创建了对象。不需要delete 来防止内存泄漏,这样做是未定义的行为。

避免使用“拥有”资源的原始指针;当您必须进行堆分配时,请改用unique_ptr。避免堆分配;学习 5 规则,只在需要时进行堆分配。

【讨论】:

  • 那么动态分配内存什么时候真正有用呢?尤其是在类内部,而不是仅仅通过函数传递。我知道这似乎是一个愚蠢的问题,因为有一百万个教程在一定程度上回答了这个问题,但我觉得我只是没有掌握指针能够做什么,而不能通过引用来完成。
  • 堆分配在以下几种情况下很有用: 1. 您在编译时不知道对象的大小。数组就是这种情况,如果您仅在运行时获得所需的大小,例如。 G。用户输入。如果您现在被告知更喜欢std::vector(是的,这样做!),那么您仍然有堆分配,它只是被容器隐藏起来...... 2.对象的生命周期比范围长它是在其中创建的。然后你有两个选择:按值返回,使用复制或移动语义 - 或者在堆上创建它,传递指针。 3.创建的对象对于栈来说太大了...
  • 谢谢你的解释...从来没有想过这些问题中的一些可以用指针来解决
【解决方案2】:

来自class.dtor#12

析构函数也通过使用 a 隐式调用 由 a 分配 构造的对象的删除表达式 新表达式;

因此,使用new 运算符分配对象时,请仅使用delete 运算符。

对象的生命周期 - 未被new 分配的对象将在超出范围时自动销毁(在您的情况下,当它超出 main 的块范围时)。

【讨论】:

    猜你喜欢
    • 2010-09-21
    • 2016-07-10
    • 2011-12-05
    • 2015-02-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多