为什么在一种情况下会发生内存泄漏,而在另一种情况下不会

Why does memory leak in one case and not in another

我正在用两种稍微不同的方式创建一个 c++ 对象,在下面的代码中,当 CASE0 时存在内存泄漏,但 CASE 中没有内存泄漏=15=]例.

#include <string>
#define CASE 1

class A {
private:
  std::string *s;
public:
  A(std::string *p_s) { s = p_s; }
};

int main() {
#if CASE==0
  auto a = A(new std::string("Hello"));
#else
  auto s = std::string("Hello");
  auto a = A(&s);
#endif
}

当我设置 CASE 0 时,valgrind 表示存在内存泄漏

valgrind ./a.out 
==24351== Memcheck, a memory error detector
==24351== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==24351== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==24351== Command: ./a.out
==24351== 
==24351== 
==24351== HEAP SUMMARY:
==24351==     in use at exit: 32 bytes in 1 blocks
==24351==   total heap usage: 2 allocs, 1 frees, 72,736 bytes allocated
==24351== 
==24351== LEAK SUMMARY:
==24351==    definitely lost: 32 bytes in 1 blocks
==24351==    indirectly lost: 0 bytes in 0 blocks
==24351==      possibly lost: 0 bytes in 0 blocks
==24351==    still reachable: 0 bytes in 0 blocks
==24351==         suppressed: 0 bytes in 0 blocks
==24351== Rerun with --leak-check=full to see details of leaked memory
==24351== 
==24351== For counts of detected and suppressed errors, rerun with: -v
==24351== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

在其他情况下(即 define CASE 1)它按预期工作并且 valgrind 没有报告任何内存泄漏。

在这两种情况下我都无法理解我正在传递一个指针并且我没有明确释放内存那么为什么它们的行为不同?

你没有内存泄漏,因为你有一个指针。

你会发生内存泄漏,因为你 new 做了一些事情但没有 delete 它。

获取指向自动存储变量的指针不会阻止变量被自动清理。

事实上,在那种情况下尝试 delete &a 将是 wrong/broken/evil/illegal/heresy。

这与以下内容没有区别:

// first case, leak
int *j = new int (5);
//
// second case, no leak
int q = 5;
int *j = &q;

在第一种情况下,我们用 new 分配了内存,我们有责任在完成后 delete 它。在第二种情况下,我们在堆栈上创建 q 并在超出范围时将其销毁。

出现此行为的原因是您的 class A 未设计为获取传递给它的 std::string* 的所有权:其 std::string *s 成员假定该对象传递给构造函数的指针将在外部销毁。

这会在对象未被销毁时导致内存泄漏:在第一种情况下,new string 永远不会调用传递给构造函数的 delete,从而导致内存泄漏。

在第二种情况下,指针指向自动存储中的一个字符串。它在 main 结束时被销毁,防止内存泄漏。

案例==0

auto a = A(new std::string("Hello"));

这意味着您正在 new-ing 堆中的对象 -> 您必须 明确地 delete 它 - 您没有在片段 -> 内存泄漏。

其他

auto s = std::string("Hello");
auto a = A(&s);
  • auto s = std::string("Hello");:这意味着您正在堆栈中创建一个对象,
  • auto a = A(&s);:获取它的地址(当然是在栈中)。
  • 一旦变量超出范围,创建的对象将被自动删除

-> 没有内存泄漏。