所以我有一个std::vector<std::shared_ptr<T>> myListOfT;
,我有一个std::weak_ptr<T> ptrToOneT;
,它是从用于填充该容器的指针之一创建的(假设我把它放在回调函数中)。std::find
该容器和我的weak_ptr
是否会为我提供原始shared_ptr
的迭代器(如果集合中存在这样的迭代器)?它是在标准中的某个地方保证的,还是依赖于此实现?
我们可以通过使用 std::weak_ptr::owner_before
在不锁定weak_ptr
的情况下逃脱。我将使用比必要的稍微冗长的解决方案并介绍owner_equal
,这是std::owner_less
对应的:
template<typename T>
class owner_equal
{
private:
template<typename L, typename R>
static bool e(L const& l, R const& r)
{ return !(l.owner_before(r)) && !(r.owner_before(l)); }
public:
using S = std::shared_ptr<T>;
using W = std::weak_ptr<T>;
bool operator()(S const& l, W const& r) const { return e(l, r); }
bool operator()(W const& l, S const& r) const { return e(l, r); }
};
使用此函数对象类型,我们可以自定义std::find_if
:
using T = int;
std::vector<std::shared_ptr<T>> myListOfT =
{std::make_shared<int>(0), std::make_shared<int>(1), std::make_shared<int>(2)};
int const pos = 1;
std::weak_ptr<T> ptrToOneT = myListOfT[pos];
auto pred = [&ptrToOneT](std::shared_ptr<T> const& e)
{ return owner_equal<T>{}(e, ptrToOneT); };
auto const r = std::find_if(begin(myListOfT), end(myListOfT), pred);
assert(r - begin(myListOfT) == pos);
lambda 可以替换为绑定表达式,例如:
auto pred = std::bind(owner_equal<T>{}, std::cref(ptrToOneT),
std::placeholders::_1);
@davidhigh建议进行优化:
template<typename FwdIt, typename T>
FwdIt findWeakPtr(FwdIt b, FwdIt e, std::weak_ptr<T> const& w)
{
if(w.expired()) return e;
else
{
auto pred = [&w](std::shared_ptr<T> const& e)
{ return owner_equal<T>{}(e, w); };
return std::find_if(b, e, pred);
}
}
(未测试)
这也略微改变了行为:如果weak_ptr
是"空的",例如从空shared_ptr
或通过默认 ctor 创建的,它将通过 owner_equal
与任何空shared_ptr
进行比较。但是,在这种情况下weak_ptr::expired
是正确的。因此,优化版本不会在范围内找到空的共享指针。
是否应该在范围中找到空的共享指针?
考虑:
using T = int;
std::vector<std::shared_ptr<T>> myListOfT =
{std::shared_ptr<T>(), std::shared_ptr<T>()};
int const pos = 1;
std::weak_ptr<T> ptrToOneT = myListOfT[pos];
auto const r = my_weak_ptr_find(begin(myListOfT), end(myListOfT), ptrToOneT);
auto const r_pos = r - begin(myListOfT);
空共享指针相等。因此,如果允许查找空的共享指针,则可以r_pos != pos && r != end(myListOfT)
。例如,此答案中算法的第一个版本产生r_pos == 0
。
有关其他上下文,请参阅:
- N1590 - 智能指针比较运营商
- 相等比较标准::weak_ptr
std::weak_ptr::lock()
是你如何将weak_ptr
"提升"为shared_ptr
:
std::weak_ptr<T> ptrToOneT;
auto observe = ptrToOneT.lock();
if (observe) {
// observe now shares ownership of the one T
}
else {
// there is no managed object or it has already
// been destroyed
}
如果lock()
成功,则您有一个普通std::shared_ptr<T>
,您可以使用它像find()
容器中的任何其他对象一样。虽然你可能不需要find()
它,因为你已经拥有它(除非你想erase()
它或其他东西)。
旁注,对于shared_ptr
,引用"原始shared_ptr
"并没有真正的意义
前我在自己的代码中遇到了类似的问题。根据我的SO研究,可以做你要求的事情。锁定弱指针,如果共享指针未过期,则使用std::find
struct A{};
int main()
{
std::vector<std::shared_ptr<A> > sptr_vec;
std::weak_ptr<A> wptr;
if(auto sptr = wptr.lock())
{
auto it = std::find(std::begin(sptr_vec), std::end(sptr_vec), sptr);
if (it != std::end(sptr_vec))
{
std::cout<<"found"<<std::endl;
}
}
}
请注意,C++标准本身在这里并不那么相关 - 共享指针比较的核心是包含的原始指针的比较,即比较内存中的地址。
或者,如果你有一个弱指针向量,你可以将std::find_if
与动态锁定的谓词一起使用:
std::vector<std::weak_ptr<A> > wptr_vec;
std::shared_ptr<A> sptr;
auto it = std::find_if(std::begin(wptr_vec), std::end(wptr_vec)
, [&sptr](auto const& w){ auto s = w.lock();
if (s) {return s == sptr;}
return false; });
if (it != std::end(wptr_vec))
{
std::cout<<"found"<<std::endl;
}
请注意,对于此应用程序,我会考虑nullptr
与自身的等价性,即nullptr == nullptr
是true
的,作为不需要的。因此,我从谓词(以及第一个代码块中的搜索)中排除了这种情况。
编辑:刚刚考虑了@dyp owner_lock
解决方案,如果只是关于搜索,这是有利的。