【问题标题】:C++ Memory Leak, Valgrind Message Misleading?C++ 内存泄漏,Valgrind 消息误导?
【发布时间】:2017-08-13 22:54:30
【问题描述】:

我对 C++ 有点陌生,并且我能够毫无错误地运行我的代码,但是,当我通过 Valgrind 运行它时,我遇到了内存泄漏,而且我一辈子都做不到似乎弄清楚我在哪里泄漏!这是我的错误信息:

==22902==     in use at exit: 72,728 bytes in 2 blocks
==22902==   total heap usage: 4 allocs, 2 frees, 73,816 bytes allocated
==22902==
==22902== 24 bytes in 1 blocks are definitely lost in loss record 1 of 2
==22902==    at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==22902==    by 0x401086: Bar::Bar(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned int) (Bar.cpp:10)
==22902==    by 0x400F76: main (Foo_main.cpp:20)

我有一个类 Foo,它被用作 Bar 类的“附件”。 Bar 继承自 foo。它有两个私有成员id_和nam​​e_,析构函数和use()在头文件中被声明为virtual。

#include "Foo.h"

#include<iostream>

using std::cout;
using std::endl;
using std::string;

Foo::Foo(int id, const string& name) :
        id_(id),
        name_(name){}

Foo::~Foo() {}

int Foo::id() const { return id_; }

string Foo::name() const { return name_; }

void Foo::use() const {
    cout << "Using Foo #" << id_ << ", " << name_ << endl;
}

Bar 有两个私有成员,num_attachments_ (unsigned int) 和 attachments_ (Foo**)

#include "Bar.h"
#include <iostream>

using std::cout;
using std::endl;

Bar::Bar(int id, const std::string& name, unsigned int num_attachments) :
        Foo(id, name),
        attachments_(new Foo*[num_attachments]),
        num_attachments_(num_attachments) {
    // explicity null out each entry in the new array
    for (unsigned int i=0; i<num_attachments; ++i) {
        attachments_[i] = NULL;
    }
}

void Bar::use() const {
    cout << "Using Bar #" << id() << endl;
    for (unsigned int i=0; i<num_attachments_; ++i) {
        if (attachments_[i] != NULL) {
            attachments_[i]->use();
        }
    }
}

(注意:我知道的一些不会导致泄漏的代码已被注释掉)。 我怀疑问题出在 Bar 的 use() 函数中,但我不太确定缺少什么!

最后,主要功能如下:

Foo* f = new Bar(1, "foobar", 3);
f->use();
delete f;

当然,我可以根据要求上传整个程序(尽管我觉得问题可能很明显,我只是完全遗漏了一些东西)。任何帮助都会很棒!

【问题讨论】:

  • 您缺少一个析构函数,它 deletes 是 newed 数组。相当基本。
  • 加1。很好,你声明了你的析构函数 virtual

标签: c++ valgrind


【解决方案1】:

您需要为 Bar 声明并实现一个显式析构函数

内存泄漏可能一定是发生了,因为你没有释放你的属性attachments_的内存,你必须在你的Bar构造函数中分配。

它的析构函数应该类似这样实现:

Bar::~Bar() {
    for (unsigned int i = 0; i < num_attachments_; i++) {
        if (attachments_[i] != NULL) {
            delete attachments_[i];
        }
    }
    if(attachments_) { // Just a safeguard good practice for defensive programming. You could omit this statement. This if statement is the same as if (attachments_ != NULL)
        delete [] attachments_;
    }
}

另外,由于Bar继承自Foo,在Bar.h中你的析构函数已经被声明为虚拟 以便在基类的析构函数之前调用派生类析构函数。由于派生类具有动态内存,因此您希望发生这种情况。所以在 Bar.h 中:

class Bar: public Foo {
   /* ...other class members... */
   public:
       /* ...other class operations... */
       virtual ~Bar(); // the virtual keyword here forces the program to visit Bar's (the derived class) destructor before Foo's (the base class)destructor. It is necessary, otherwise it only invokes the Foo's destructor (leaving leaked dynamic memory from Bar)
};

【讨论】:

  • 哇,我不敢相信我错过了,非常感谢!我不再遇到泄漏,但是,在更复杂的问题中,在 for 循环之后添加“delete [] attachments_”是否更合适,因为它是 Foo** 类型的?
  • 你是正确的。我匆匆忙忙,错过了。我现在已经编辑了我的答案。
  • 顺便说一句:没有理由在删除之前检查 NULL(请参阅 stackoverflow.com/questions/8004495/deleting-a-null-pointerstackoverflow.com/questions/615355/…
  • @Frunsi plus1,如果你真的知道自己在做什么,那就是真的。但是,这是一个很好的做法。应用它并没有什么坏处,尤其是在开始使用 C++ 内存管理时。
【解决方案2】:

尝试对 Foo Bar 对象使用 std::unique_ptr。

http://en.cppreference.com/w/cpp/memory/unique_ptr

【讨论】:

    猜你喜欢
    • 2020-03-31
    • 2016-03-15
    • 1970-01-01
    • 1970-01-01
    • 2015-06-28
    • 1970-01-01
    • 2013-06-24
    • 2019-07-02
    • 2021-11-28
    相关资源
    最近更新 更多