You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用weak_ptr仍出现内存泄漏?两种shared_ptr用法的困惑

Why does my first shared_ptr/weak_ptr code have memory leaks but the second doesn't?

Let's break down what's happening in both examples, because the key issue here is misunderstanding how weak_ptr actually solves circular references.

First Example: You're still creating a circular shared_ptr reference

In your first main function:

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();
}

The problem is that wp_sB.lock() returns a shared_ptr<spyder> pointing to sB, and you store that in sA->finger (which is a shared_ptr<spyder>). Same goes for sB->finger pointing to sA via wp_sA.lock().

This creates a classic circular reference:

  • sA's reference count is incremented by sB->finger
  • sB's reference count is incremented by sA->finger

When main exits, sA and sB (the original shared_ptrs) are destroyed, which decrements each reference count by 1. But each count is still 1 (because the other spyder's finger shared_ptr is still holding a reference). So neither spyder object is deleted, causing the memory leak Valgrind reported.

You created weak_ptrs, but you immediately converted them back to shared_ptrs and stored those—so the weak_ptrs never actually did their job of breaking the cycle.

Second Example: No circular reference exists (but it's not a valid fix)

In your second main function:

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();
}

Here's what's different:

  1. sA and sB are stack-allocated objects—they don't live on the heap, so they're automatically destroyed when main exits, no need for shared_ptr cleanup.
  2. The weak_ptrs wp_sA and wp_sB point to completely separate heap-allocated spyder objects (the ones created by std::make_shared<spyder>("A") and std::make_shared<spyder>("B")).
  3. sA.finger holds a shared_ptr to that separate "B" object, and sB.finger holds a shared_ptr to that separate "A" object.

When main exits:

  • The stack-allocated sA and sB are destroyed, which destroys their finger shared_ptr members.
  • Each of those separate heap spyder objects has their reference count drop to 0, so they're deleted properly.

There's no circular reference here because the shared_ptrs in finger point to objects that aren't referencing each other back in a way that keeps their counts above 0. But this example doesn't actually solve the original circular reference problem—it just avoids it entirely by using unrelated objects.

The Correct Fix: Use weak_ptr for the class member

To properly fix the circular reference issue, you need to change the finger member of the spyder class to a weak_ptr<spyder> instead of a shared_ptr<spyder>. Here's how:

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

int main(){
    auto sA = std::make_shared<spyder>("A");
    auto sB = std::make_shared<spyder>("B");
    sA->finger = sB; // Assign shared_ptr to weak_ptr directly
    sB->finger = sA;
}

Now, when main exits:

  • sA and sB (the original shared_ptrs) are destroyed, decrementing each reference count to 0.
  • The weak_ptr members in each spyder don't contribute to the reference count, so there's no cycle holding the objects alive. Both spyder objects are deleted properly, and Valgrind won't report a leak.

When you need to access the finger object later, you can use lock() to get a temporary shared_ptr (which is safe as long as the object still exists):

if (auto ptr = sA->finger.lock()) {
    // Use ptr safely here
    std::cout << ptr->ask_name() << std::endl;
}

内容的提问来源于stack exchange,提问作者curlywei

火山引擎 最新活动