【问题标题】:memory leak and I don't know why内存泄漏,我不知道为什么
【发布时间】:2022-01-08 22:38:26
【问题描述】:

我的第一个问题是添加地图的对象A(v),退出范围时应该自动删除吗?

我的第二个问题是,当程序退出时,添加到地图中的对象会发生什么?我相信当我执行 a_[name] = A(v); 时,会将副本存储到地图中。 另外,我需要提供一个拷贝构造函数吗?

void B::AddA(std::string name, int v) {
    a_[name] = A(v);
}

我的最后一个问题是我没有用“new”创建任何对象,我不应该删除任何对象。

我不明白泄漏是从哪里来的。

感谢您的帮助。谢谢。

完整代码

#include <map>
#include <string>
#include <iostream>

class A {
    public:
        int vala_;
        A();
        ~A();
        A(int v);
};

A::A() {
    vala_ = 0;
}

A::~A() {}

A::A(int v) {
    vala_ = v;
}


class B {
    public:
        int valb_;
        std::map<std::string, A> a_;
        B();
        ~B();
        void AddA(std::string name, int v);
};

B::B() {
    valb_ = 0;
}

B::~B() {
}

void B::AddA(std::string name, int v) {
    a_[name] = A(v);
}


int main() {
    B b;
    b.AddA("wewe", 5);
    std::cout << b.a_["wewe"].vala_ << std::endl;
    exit(0);
}

valgrind

I replaced the number ==????==, to ==xxxx==. I guess it was the process id. 
==xxxx== Memcheck, a memory error detector
==xxxx== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==xxxx== Using Valgrind-3.16.1 and LibVEX; rerun with -h for copyright info
==xxxx== Command: ./a.out --leak-check=full -s
==xxxx==
5
==xxxx==
==xxxx== HEAP SUMMARY:
==xxxx==     in use at exit: 72 bytes in 1 blocks
==xxxx==   total heap usage: 3 allocs, 2 frees, 73,800 bytes allocated
==xxxx==
==xxxx== LEAK SUMMARY:
==xxxx==    definitely lost: 0 bytes in 0 blocks
==xxxx==    indirectly lost: 0 bytes in 0 blocks
==xxxx==      possibly lost: 0 bytes in 0 blocks
==xxxx==    still reachable: 72 bytes in 1 blocks
==xxxx==         suppressed: 0 bytes in 0 blocks
==xxxx== Rerun with --leak-check=full to see details of leaked memory
==xxxx==
==xxxx== For lists of detected and suppressed errors, rerun with: -s
==xxxx== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

【问题讨论】:

  • exit(0) 不是可返回函数。 b 没有被销毁。使用普通的return 0
  • @273K 或者什么都没有。

标签: c++ object memory-leaks valgrind


【解决方案1】:
==xxxx==     in use at exit: 72 bytes in 1 blocks

==xxxx==    still reachable: 72 bytes in 1 blocks

这些仅意味着当程序退出时,您仍然有引用的活动内存。内存并没有完全丢失,这通常被称为严格意义上的内存泄漏,并将在definitely lostindirectly lostpossibly lost 下列出。当程序结束时,是否还有未释放的内存并不重要。

但是,这仍然可能是问题的征兆,例如,如果应该销毁且具有带副作用的析构函数的对象没有运行。

在您的情况下,问题是exit(0) 调用。调用std::exit 会在此处结束程序并进行一些清理。清理包括销毁具有静态存储期限的对象,但不包括具有自动存储期限的对象,这些对象通常会在其范围离开时被销毁。

在你的情况下B b;,包括它存储的所有元素,通常会在main}return 语句中被销毁,但是因为你事先调用了exit,所以它永远不会被销毁.在这种特殊情况下,这不是问题,但如果例如b 是一个带有析构函数的对象,它应该执行一些在程序外可见副作用的操作,它可能是。

您不应调用exit(0)main 退出程序。只需使用return 0; 或完全不使用它,因为对于main,特别是没有返回语句等同于return 0;


旁注:您不应显式声明/定义不做任何事情且不是virtual 的析构函数,例如A::~A() {}。如果你根本没有在类中声明析构函数,编译器会自动为你生成它,并且行为完全相同。

无论如何手动声明析构函数都会对特殊成员函数的其他隐式生成产生影响,这可能会影响程序的性能,并且还会使始终遵循rule of 0/3/5 变得更加困难。


我的第一个问题是添加地图的对象A(v),退出范围时应该自动删除吗?

A(v) 是一个临时对象,将在完整表达式a_[name] = A(v) 的末尾被销毁。

另外,我需要提供一个拷贝构造函数吗?

不,如果您不手动声明一个(与析构函数相同),编译器会隐式声明一个,并且假设这是可能的,它将被定义为简单地复制每个成员。这通常是你想要的。

我的最后一个问题是我没有用“new”创建任何对象,我不应该删除任何对象。

是的,完全正确。

【讨论】:

  • 您不应该显式声明/定义不做任何事情且不是虚拟的析构函数,例如 A::~A() {} -- 或者将析构函数声明为= default;
  • @PaulMcKenzie 即使声明并默认它,仍然会禁止隐式移动构造函数/赋值,我认为这会令人困惑:godbolt.org/z/Mrd3YG878 但如果所有其他特殊成员函数都是显式的,那当然是有意义的也被默认/删除。
【解决方案2】:

“仍然可达”并不严格意味着它是memory leak。我相信这是因为你调用了exit(0) 而不是仅仅返回 0。堆栈没有被清理,因为程序被信号终止了。

【讨论】:

  • 不,不是信号。 exit 会从您调用它的任何位置生成一个干净的退出,但它不会展开堆栈。
猜你喜欢
  • 1970-01-01
  • 2012-01-01
  • 2013-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-09
相关资源
最近更新 更多