使用weak_ptr仍出现内存泄漏?两种shared_ptr用法的困惑
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 bysB->fingersB's reference count is incremented bysA->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:
sAandsBare stack-allocated objects—they don't live on the heap, so they're automatically destroyed whenmainexits, no need for shared_ptr cleanup.- The
weak_ptrswp_sAandwp_sBpoint to completely separate heap-allocatedspyderobjects (the ones created bystd::make_shared<spyder>("A")andstd::make_shared<spyder>("B")). sA.fingerholds a shared_ptr to that separate "B" object, andsB.fingerholds a shared_ptr to that separate "A" object.
When main exits:
- The stack-allocated
sAandsBare destroyed, which destroys theirfingershared_ptr members. - Each of those separate heap
spyderobjects 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:
sAandsB(the original shared_ptrs) are destroyed, decrementing each reference count to 0.- The
weak_ptrmembers in eachspyderdon't contribute to the reference count, so there's no cycle holding the objects alive. Bothspyderobjects 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




