【问题标题】:Why does memory leak in one case and not in another为什么在一种情况下会发生内存泄漏,而在另一种情况下不会
【发布时间】:2019-01-02 14:06:43
【问题描述】:

我正在用两种略有不同的方式创建一个c++ 对象,在下面的代码中,当CASE0 时,存在内存泄漏,但在else 情况下没有内存泄漏。

#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 它。

标签: c++ memory-leaks valgrind


【解决方案1】:

这种行为的原因是您的类A 并非旨在获取传递给它的std::string* 的所有权:它的std::string *s 成员假定传递给构造函数的指针的对象将被销毁外部。

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

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

【讨论】:

    【解决方案2】:

    您不会因为有指针而发生内存泄漏。

    你得到内存泄漏是因为你new'd 某事而没有delete它。

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

    事实上,在这种情况下尝试delete &amp;a 是错误的/破坏的/邪恶的/非法的/异端的。

    【讨论】:

      【解决方案3】:

      CASE==0

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

      这意味着你 new-ing 堆中的对象 -> 你必须明确 delete 它 - 你没有在 sn-p -> 内存泄漏。

      其他

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

      -> 没有内存泄漏。

      【讨论】:

        【解决方案4】:

        这与:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-01-16
          • 1970-01-01
          • 1970-01-01
          • 2013-12-28
          相关资源
          最近更新 更多