[英]A set of weak_ptr
這是代碼:
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
}
我想知道如何count/find
存儲在intset
的weak_ptr<int>
以及是否有更好的方法可以完成同樣的工作?
您不能將臨時 shared_ptr 插入一組弱指針,因為從這個存儲的弱指針指向已刪除的內存的意義上說,這是內存泄漏。
intset.insert(make_shared<int>(1));
// after this instruction shared_ptr destructor frees the memory
這就是為什么你不能在 set 中找到它 - 因為*lhs.lock()
在這里是 UB。
您需要以這種方式制作 ò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;
}
};
所有這一切意味着 - 你需要有這個 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
}
有了上述 - 您的計數將起作用。
還考慮保持 shared_ptr 設置...
[更新]
marko 在評論中指出了有效的問題。 std::weak_ptr 根本不能以您使用它的方式用作鍵。 只有當你能確保指向的值永遠不會改變,指針本身也永遠不會過期。 看這個例子:
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
另一個例子:
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
您可以保留 std::shared_ptr 以防止指針的設置過期 - 並且 std::shared_ptr 具有operator <
- 但該運算符比較指針本身 - 而不是指向的值 - 所以std::set<std::shared_ptr<int>>
更好std::set<std::shared_ptr<int>>
- 但最好的是std::set<int>
或更改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;
});
或者使用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
沒有實現您似乎假設的享元模式。
make_shared
返回一個可以共享的指針。 要獲得更多指向同一對象的指針,您必須使用復制構造函數或復制賦值運算符,並傳遞現有的shared_ptr
。
make_shared
不會生成指向現有對象的附加指針。 它創建一個新對象。
因此, intset.count(make_shared<int>(1))
返回0
是正確的。 剛剛創建的shared_ptr<int>
在集合中的任何地方都不存在。
連續調用make_shared<int>(1)
比較不相等。
然后是與您的比較功能相關的額外損壞。 有一個適用於weak_ptr
的排序,但事實並非如此。 你不穩定的比較函數會導致set
行為異常。
您應該簡單地使用set<int>
。
我們可以使用標准的std::owner_less<>
代替嘗試為弱指針編寫自己的比較函數並提出行為不端的解決方案。
除非您實現清理方法並定期使用它,否則擁有一組弱指針是一個壞主意。 您可能希望在比較函數中設置保護措施,因為目前結果未定義。 以@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());
}
};
使用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(); }
);
}
您可以使用靜態共享指針來存儲查詢(盡管這有點難看):
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);
}
和一個例子:
#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";
}
將 weak_pointer 包裝在容器中
例如
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();}
};
並將其用作:
std::set<WeakPtrAsKey<MyKey>> mySet;
std::map<WeakPtrAsKey<MyKey>,MyVal> myMap;
用法示例:
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.