在C++中std::shared_ptr可以实现多个对象共享同一块内存,但存在循环引用的问题。即两个shared_ptr互相指向对方,导致引用计数无法被递减到0,造成内存泄露。下面看一个有问题的例子:
#include <iostream>
#include <memory>
class Any {
public:
friend bool set_relationship(std::shared_ptr<Any> & p1,
std::shared_ptr<Any> & p2) {
if (!p1 || !p2) {
return false;
}
p1->m_another = p2;
p2->m_another = p1;
return true;
}
private:
std::shared_ptr<Any> m_another;
};
int main(void) {
auto p1 = std::make_shared<Any>();
auto p2 = std::make_shared<Any>();
set_relationship(p1, p2);
return 0;
}
通过valgrind 工具进行内存检查:
==1996== LEAK SUMMARY:
==1996== definitely lost: 32 bytes in 1 blocks
==1996== indirectly lost: 32 bytes in 1 blocks
==1996== possibly lost: 0 bytes in 0 blocks
==1996== still reachable: 0 bytes in 0 blocks
==1996== suppressed: 0 bytes in 0 blocks
使用shared_ptr导致循环引用,的确造成了内存泄露。
下面看一个使用weak_ptr的例子:
#include <iostream>
#include <memory>
class Any {
public:
Any(int a) : m_a(a) {}
friend bool set_relationship(std::shared_ptr<Any> &p1,
std::shared_ptr<Any> &p2) {
if (!p1 || !p2) {
return false;
}
// weak_ptr重载的赋值运算符中可以接收shared_ptr对象
p1->m_another = p2;
p2->m_another = p1;
return true;
}
void show(void) { std::cout << m_a << std::endl; }
std::weak_ptr<Any> &get_ptr(void) { return m_another; }
private:
int m_a;
std::weak_ptr<Any> m_another;
};
int main(void) {
auto p1 = std::make_shared<Any>(1);
auto p2 = std::make_shared<Any>(2);
set_relationship(p1, p2);
assert(p1.use_count() == 1);
assert(p2.use_count() == 1);
p1->get_ptr().lock()->show(); // 输出:2
return 0;
}
通过valgrind 工具进行内存检查:
==4775== HEAP SUMMARY:
==4775== in use at exit: 0 bytes in 0 blocks
==4775== total heap usage: 3 allocs, 3 frees, 72,768 bytes allocated
==4775==
==4775== All heap blocks were freed -- no leaks are possible
通过weak_ptr 能够解决shared_ptr循环引用带来的内存泄露问题。