A set of weak_ptr
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
这就是为什么您在集合中找不到它的原因——因为*lhs.lock()
在这里是UB。
请参见weak_ptr::lock文档。
您需要以这种方式使您的订单操作员:
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 sowmews来计数:
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保留在集合中。。。
[更新]
马尔科在评论中指出了有效的问题。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<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;
});
我们可以使用标准的std::owner_less<>
,而不是试图为弱指针编写自己的比较函数并提出错误的解决方案。
shared_ptr
并没有实现您似乎认为的轻量级模式。
CCD_ 14返回能够被共享的指针。若要获得指向同一对象的更多指针,必须使用复制构造函数或复制赋值运算符,并传递现有的shared_ptr
。
make_shared
不会为现有对象创建额外的指针。它会创建一个新对象。
因此,intset.count(make_shared<int>(1))
返回0
是正确的。刚刚创建的shared_ptr<int>
不存在于集合中的任何位置。
对make_shared<int>(1)
的连续调用的比较不相等。
然后是与你的比较函数相关的额外破碎。有一个排序适用于weak_ptr
,但事实并非如此。您不稳定的比较函数会导致set
行为不端。
您应该简单地使用set<int>
。
除非实现一个清理方法并定期使用它,否则拥有一组弱指针是个坏主意。您可能希望在比较函数中设置一个保护措施,因为目前结果尚未定义。以@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();
}
- CLANG 编译器 说:变量"PTR"可能未初始化
- 在以唯一ptr为值的C++映射中,动态内存何时会被销毁
- 将 ptr 传递给 ptr 到 A 作为参数传递给 A 的函数是不好的做法吗?
- 为共享 ptr 向量实现复制 c'tor?
- 字符和整数中 **(ptr+1) 的值差异
- C++:在不中断共享的情况下通过引用传递共享 PTR?
- 为什么"weak.lock()"返回"nullptr" "auto weak=std::make_shared<int>(42);"的定义?
- 如何将派生类从基 ptr 分配给 nlohmann::json
- 引用 std::shared:ptr 以避免引用计数
- 为什么我不能在不进行任何转换的情况下将浮点数放入任何类型的 ptr 中?
- 在调用函数时,ptr** 和 ptr*& 之间是否有区别,或者首选C++?
- 另一种类型的智能ptr,比如具有弱refs的unique_ptr
- 尝试打印出 *ptr++ 的值,以了解它是如何工作的
- 如何控制共享 ptr 引用计数?
- C++中的指针否定 (!ptr == NULL)
- 从const ptr*转换为ptr*时出现问题
- 这是MSVC 2013中具有共享PTR的单例的正确实现吗?
- 对唯一 ptr 无效读取的引用向量
- C++ 类型转换基础 PTR 到派生 PTR 保存在引用类中
- 为什么使用模板生成的函数具有"weak"符号类型?