c++ - 关于 "circular reference",我使用了 weak_ptr 但内存泄漏仍然发生

标签 c++ shared-ptr smart-pointers circular-reference weak-ptr

我读了:

How to avoid memory leak with shared_ptr?

我知道我需要使用weak_ptr 来避免循环引用

所以我创建了一个小程序来播放循环引用

以下对象(spyder)将被调用

class spyder {
 public:
  spyder(std::string _name): 
    m_name(_name), finger(nullptr)
  {  }
  inline const std::string ask_name() const{
    return m_name;
  }
  std::shared_ptr<spyder> finger;
 private:
  std::string m_name;
};

我在主代码中使用 shared_ptr 和 weak_ptr 调用 spyder:

int main(){
  auto sA = std::make_shared<spyder>("A");
  auto sB = std::make_shared<spyder>("B");
  std::weak_ptr<spyder> wp_sA(sA);
  std::weak_ptr<spyder> wp_sB(sB);  
  sA->finger = wp_sB.lock();
  sB->finger = wp_sA.lock();
}

以上代码发生了内存泄漏(使用valgrind检查)

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

但是在我将上面的代码修改为:

int main(){
  spyder sA("A"), sB("B");
  std::weak_ptr<spyder> wp_sA( std::make_shared<spyder>("A") ) ;
  std::weak_ptr<spyder> wp_sB( std::make_shared<spyder>("B") );
  sA.finger = wp_sB.lock();
  sB.finger = wp_sA.lock();
}

内存泄漏没有发生,

==20695== Memcheck, a memory error detector
==20695== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==20695== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==20695== Command: ./t
==20695== 
==20695== 
==20695== HEAP SUMMARY:
==20695==     in use at exit: 0 bytes in 0 blocks
==20695==   total heap usage: 3 allocs, 3 frees, 72,832 bytes allocated
==20695== 
==20695== All heap blocks were freed -- no leaks are possible
==20695== 
==20695== For counts of detected and suppressed errors, rerun with: -v
==20695== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

我对此感到困惑。

最佳答案

你根本没有解决循环依赖。

在你的第一个版本中,

sAshared_ptr 管理,并将shared_ptr 存储到sBsB 又由 shared_ptr 管理,并将 shared_ptr 存储到 sA。这意味着它们的引用计数永远不会变为 0。

相反,finger 应该是 std::weak_ptr 类型,您应该只在需要使用它之前lock() 它。

class spyder {
 public:
  spyder(std::string _name): 
    m_name(_name), finger()
  {  }
  inline const std::string ask_name() const{
    return m_name;
  }
  std::weak_ptr<spyder> finger;
 private:
  std::string m_name;
};

int main(){
  auto sA = std::make_shared<spyder>("A");
  auto sB = std::make_shared<spyder>("B");
  sA->finger = sB;
  sB->finger = sA;
}

你的第二个版本

从临时 shared_ptr 构造 weak_ptr,这意味着在构造之后您的 weak_ptrexpired()sA.fingersB.finger 都存储了 nullptr 在此版本中(但没有内存泄漏)。

关于c++ - 关于 "circular reference",我使用了 weak_ptr 但内存泄漏仍然发生,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57851897/

相关文章:

c++ - WM_TIMER 动画闪烁

c++ - 共享 void 指针。为什么这行得通?

c++ - CComPtr 通过引用传递

c++ - 如何连接几张 map ?

c++ - 使用 enable_if 匹配数字作为函数参数

c++ - 为什么 shared_ptr<void> 合法,而 unique_ptr<void> 格式不正确?

c++ - "std::shared_from_this"不能被它的派生类继承吗?

c++ - 如何安全地填充 Boosts 的指针容器?

c++ - 在 Windows 中从文件名获取驱动器号

c++11 - 无法消除共享指针泄漏的递归解析代码