为何weak_ptr无==比较运算符?vector<weak_ptr>元素删除困境咨询
weak_ptr have a == comparison operator? Great question! This is actually an intentional design choice from the C++ standards committee, rooted in the unique nature of weak_ptr as a weak reference. Let me break this down for you:
First, remember that weak_ptr doesn't own the object it points to—it only tracks the lifetime of an object managed by shared_ptr. The problem with adding a == operator is that it's ambiguous what exactly should be compared:
- Should it check if the underlying raw pointers are the same? But if one
weak_ptrhas expired (all associatedshared_ptrs have been destroyed), its raw pointer might benullptr—and another expiredweak_ptrfrom a completely different object could also benullptr, leading to a misleadingtrueresult. - Or should it check if both
weak_ptrs are tied to the same control block (i.e., tracking the sameshared_ptr's lifecycle)? That's a more semantically meaningful check, but using==for this would confuse many developers who'd assume it's comparing raw pointers directly.
Now, onto your specific problem with vector<weak_ptr<Type>> and erase(remove()): you're right that without ==, that approach won't work. But please don't use _Get()—that's a compiler-specific private implementation detail. Relying on it makes your code non-portable, and it could change without warning in future compiler versions.
Instead, use the standard weak_ptr interface designed for exactly this kind of comparison: owner_before. This method defines a strict weak ordering, and you can use it to check if two weak_ptrs are associated with the same control block (i.e., they're referencing the same object's weak reference).
Here's how you'd safely remove elements matching a target weak_ptr:
#include <vector> #include <memory> #include <algorithm> int main() { std::vector<std::weak_ptr<int>> wp_list; auto my_shared = std::make_shared<int>(42); std::weak_ptr<int> target = my_shared; wp_list.push_back(target); wp_list.push_back(std::weak_ptr<int>(std::make_shared<int>(100))); wp_list.push_back(target); // Erase all weak_ptrs tied to the same control block as 'target' wp_list.erase( std::remove_if(wp_list.begin(), wp_list.end(), [&target](const std::weak_ptr<int>& wp) { // If neither is ordered before the other, they share the same control block return !wp.owner_before(target) && !target.owner_before(wp); }), wp_list.end()); return 0; }
If your goal is to clean up expired weak_ptrs (those pointing to objects that have already been destroyed), it's even simpler—just check expired():
wp_list.erase( std::remove_if(wp_list.begin(), wp_list.end(), [](const std::weak_ptr<int>& wp) { return wp.expired(); }), wp_list.end());
To wrap things up: the lack of a == operator for weak_ptr isn't an oversight—it's a deliberate choice to avoid semantic confusion. The standard gives you all the tools you need (owner_before, expired, lock) to work with weak_ptrs safely and portably, so there's no need to dig into private implementation details.
内容的提问来源于stack exchange,提问作者Deadfish

