C++ std::weak_ptr

在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 循环引用带来的内存露问题. 如果觉得有帮助,可以扫描右边的微信打赏码支持一下.

Leave a Reply

Your email address will not be published. Required fields are marked *