[英]A set of weak_ptr
Here is the code:这是代码:
struct lex_compare {
bool operator() (const weak_ptr<int> &lhs, const weak_ptr<int> &rhs)const {
return *lhs.lock() < *rhs.lock();
}
};
int main(){
set<weak_ptr<int>,lex_compare> intset;
intset.insert(make_shared<int>(1));
cout << "intset size:" << intset.size() << endl; //1
cout << "Does 1 exist?"<< intset.count(make_shared<int>(1))<<endl; // failed
}
I want to know how to count/find
the weak_ptr<int>
stored in intset
and if a better method is available to do the same work?我想知道如何count/find
存储在intset
的weak_ptr<int>
以及是否有更好的方法可以完成同样的工作?
You cannot insert temporary shared_ptr to set of weak pointers because it is memory leak in the sense that this stored weak pointer points to already deleted memory.您不能将临时 shared_ptr 插入一组弱指针,因为从这个存储的弱指针指向已删除的内存的意义上说,这是内存泄漏。
intset.insert(make_shared<int>(1));
// after this instruction shared_ptr destructor frees the memory
That is why you cannot find it in set - because *lhs.lock()
is UB here.这就是为什么你不能在 set 中找到它 - 因为*lhs.lock()
在这里是 UB。
See weak_ptr::lock doc .请参阅weak_ptr::lock 文档。
You need to make your òrder operator in this way:您需要以这种方式制作 òrder 运算符:
struct lex_compare {
bool operator() (const weak_ptr<int> &lhs, const weak_ptr<int> &rhs)const {
auto lptr = lhs.lock(), rptr = rhs.lock();
if (!rptr) return false; // nothing after expired pointer
if (!lptr) return true; // every not expired after expired pointer
return *lptr < *rptr;
}
};
All that means - you need to have this shared_ptr sowmewhere to count it:所有这一切意味着 - 你需要有这个 shared_ptr sowmewhere 来计算它:
int main(){
set<weak_ptr<int>,lex_compare> intset;
auto shared1 = make_shared<int>(1);
intset.insert(shared1);
cout << "intset size:" << intset.size() << endl; //1
cout << "Does 1 exist?"<< intset.count(make_shared<int>(1))<<endl; // failed
}
With the above - your count will work.有了上述 - 您的计数将起作用。
Consider also to keep shared_ptr in set...还考虑保持 shared_ptr 设置...
[UPDATE] [更新]
marko in comments pointed the valid issue. marko 在评论中指出了有效的问题。 std::weak_ptr cannot be used as a key in a way you are using it at all. std::weak_ptr 根本不能以您使用它的方式用作键。 Only if you can ensure that pointed value will never change nor pointer itself will never expire.只有当你能确保指向的值永远不会改变,指针本身也永远不会过期。 See this example:看这个例子:
set<weak_ptr<int>,lex_compare> intset;
auto shared1 = make_shared<int>(1);
intset.insert(shared1);
cout << "Does 1 exist?"<< intset.count(make_shared<int>(1))<<endl; // works
shared1.reset();
cout << "Does 1 exist?"<< intset.count(make_shared<int>(1))<<endl; // failed
And the other example:另一个例子:
set<weak_ptr<int>,lex_compare> intset;
auto shared1 = make_shared<int>(1);
intset.insert(shared1);
cout << "Does 1 exist?"<< intset.count(make_shared<int>(1))<<endl; // works
*shared1 = 2;
cout << "Does 1 exist?"<< intset.count(make_shared<int>(1))<<endl; // failed
You can keep std::shared_ptr which prevents from out-of-set expiration of pointer - and std::shared_ptr has operator <
- but this operator compares pointers themselves - not the pointed values - so better is std::set<std::shared_ptr<int>>
- but the best would be std::set<int>
您可以保留 std::shared_ptr 以防止指针的设置过期 - 并且 std::shared_ptr 具有operator <
- 但该运算符比较指针本身 - 而不是指向的值 - 所以std::set<std::shared_ptr<int>>
更好std::set<std::shared_ptr<int>>
- 但最好的是std::set<int>
Or change std::set<...>
--> std::vector<std::weak_ptr<int>>
- and use count_if
-- see:或更改std::set<...>
--> std::vector<std::weak_ptr<int>>
- 并使用count_if
-- 请参阅:
vector<weak_ptr<int>> intset;
auto shared1 = make_shared<int>(1);
intset.push_back(shared1);
cout << "Does 1 exist?"<< count_if(begin(intset), end(intset),
[](auto&& elem)
{
auto ptr = elem.lock();
return ptr && *ptr == 1;
});
Or with std::set<std::shared_ptr<int>>
:或者使用std::set<std::shared_ptr<int>>
:
set<shared_ptr<int>> intset;
auto shared1 = make_shared<int>(1);
intset.insert(shared1);
// if you can ensure shared1 value will not change:
cout << "Does 1 exist?"<< intset.count(shared1);
// if not - use count_if - the slower than std::count
cout << "Does 1 exist?"<< count_if(begin(intset), end(intset),
[](auto&& ptr)
{
return ptr && *ptr == 1;
});
shared_ptr
does NOT implement flyweight pattern, which you seem to assume. shared_ptr
没有实现您似乎假设的享元模式。
make_shared
returns a pointer that is capable of being shared. make_shared
返回一个可以共享的指针。 To get more pointers to the same object, you must use copy constructor or copy assignment operator, and pass the existing shared_ptr
.要获得更多指向同一对象的指针,您必须使用复制构造函数或复制赋值运算符,并传递现有的shared_ptr
。
make_shared
does NOT make an additional pointer to an existing object. make_shared
不会生成指向现有对象的附加指针。 It creates a new object.它创建一个新对象。
Therefore, it is correct that intset.count(make_shared<int>(1))
returns 0
.因此, intset.count(make_shared<int>(1))
返回0
是正确的。 The just-created shared_ptr<int>
does not exist anywhere in the set.刚刚创建的shared_ptr<int>
在集合中的任何地方都不存在。
Successive calls to make_shared<int>(1)
do not compare equal.连续调用make_shared<int>(1)
比较不相等。
Then there's the additional brokenness associated with your comparison function.然后是与您的比较功能相关的额外损坏。 There is an ordering that works for weak_ptr
, but that is not it.有一个适用于weak_ptr
的排序,但事实并非如此。 Your unstable comparison function will cause set
to badly misbehave.你不稳定的比较函数会导致set
行为异常。
You should use simply set<int>
.您应该简单地使用set<int>
。
我们可以使用标准的std::owner_less<>
代替尝试为弱指针编写自己的比较函数并提出行为不端的解决方案。
It's a bad idea to have a set of weak pointers unless you implement a cleanup method and use it regularly.除非您实现清理方法并定期使用它,否则拥有一组弱指针是一个坏主意。 You might want to put a safeguard in your comparison function because at present the result is undefined.您可能希望在比较函数中设置保护措施,因为目前结果未定义。 Taking the advice from @PiotrNycz for example:以@PiotrNycz 的建议为例:
template <class T>
struct wptr_less_than
{
bool operator() ( const std::weak_ptr<T>& lhs, const std::weak_ptr<T>& rhs ) const {
return lhs.expired() || (!rhs.expired() && *lhs.lock() < *rhs.lock());
}
};
Use a combination of count_if
and weak_ptr::expired
:使用count_if
和weak_ptr::expired
的组合:
template <class T, class C, class A>
size_t count_valid_pointers( const std::set< std::weak_ptr<T>, C, A >& s )
{
return s.size() - std::count_if( s.begin(), s.end(),
[]( const std::weak_ptr<T>& wptr ){ return wptr.expired(); }
);
}
You can use a static shared pointer to store the query (although this is kind of ugly):您可以使用静态共享指针来存储查询(尽管这有点难看):
template <class T, class C, class A>
typename std::set< std::weak_ptr<T>, C, A >::iterator
find_value( const std::set< std::weak_ptr<T>, C, A >& s, const T& val )
{
static auto query = std::make_shared<T>();
query.reset( const_cast<T*>(&val), []( T* ){} ) ;
return s.find(query);
}
And an example:和一个例子:
#include <algorithm>
#include <iostream>
#include <memory>
#include <set>
template <class T>
struct wptr_less_than
{
bool operator() ( const std::weak_ptr<T>& lhs, const std::weak_ptr<T>& rhs ) const {
return lhs.expired() || (!rhs.expired() && *lhs.lock() < *rhs.lock());
}
};
template <class T, class C, class A>
size_t count_valid_pointers( const std::set< std::weak_ptr<T>, C, A >& s )
{
return s.size() - std::count_if( s.begin(), s.end(),
[]( const std::weak_ptr<T>& wptr ){ return wptr.expired(); }
);
}
template <class T, class C, class A>
typename std::set< std::weak_ptr<T>, C, A >::iterator
find_value( const std::set< std::weak_ptr<T>, C, A >& s, const T& val )
{
static auto query = std::make_shared<T>();
query.reset( const_cast<T*>(&val), []( T* ){} ) ;
return s.find(query);
}
int main()
{
std::set< std::weak_ptr<int>, wptr_less_than<int> > intset;
auto a = std::make_shared<int>(1);
auto b = std::make_shared<int>(2);
intset.insert(a); intset.insert(b); a.reset();
std::cout << "intset size:" << intset.size() << std::endl; //2
std::cout << "intset real size:" << count_valid_pointers(intset) << std::endl; //1
if ( find_value(intset,2) != intset.end() )
std::cout << "Found it!\n";
}
wrap up the weak_pointer in a container将 weak_pointer 包装在容器中
eg例如
template <class T> class WeakPtrAsKey {
T * m_ptr;
typedef std::shared_ptr<T> _Sptr;
typedef std::weak_ptr<T> _Wptr;
_Wptr m_wptr;
public:
WeakPtrAsKey():m_ptr(nullptr) {};
WeakPtrAsKey(_Wptr wptr):m_ptr(wptr.lock().get()),m_wptr(wptr) {}
WeakPtrAsKey(_Sptr sptr):m_ptr(sptr.get()),m_wptr(sptr) {}
bool operator<(const WeakPtrAsKey<T> &other) const { return m_ptr<other.m_ptr;}
bool operator==(const WeakPtrAsKey<T> &other) const { return m_ptr==other.m_ptr;}
_Wptr getWeak() const { return m_wptr;}
_Sptr lock() const { return m_wptr.lock();}
};
and use it as:并将其用作:
std::set<WeakPtrAsKey<MyKey>> mySet;
std::map<WeakPtrAsKey<MyKey>,MyVal> myMap;
usage examples:用法示例:
void addToMap(std::weak_ptr<MyKey> key, const MyVal &val)
{
myMap[key]=val
}
void addToMap(std::shared_ptr<MyKey> key, const MyVal &val)
{
myMap[key]=val
}
std::shared_ptr<MyKey> getFirstKey()
{
auto it=myMap.begin();
return=it->first.lock();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.