我们可以使用
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
或通过默认构造函数创建的,则它将通过
owner_equal
与任何空的
shared_ptr
相等。但是,在这种情况下,
weak_ptr::expired
返回true。因此,优化版本将无法在范围内找到空的共享指针。
应该在范围内找到空的共享指针吗?
考虑:
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
。
额外的背景信息,请参见:
get()
返回的值转换为绝对基指针。 - Captain Obvliousweak_ptr::lock()
获得一个shared_ptr
,然后将其传递给std::find
。您将找到指向相同对象的某些指针。 - Igor Tandetnikweak_ptr
时,你可能可以使用.lock()
从中获取一个shared_ptr
,也可能不行。没有必要搜索以找到指针。如果你想要迭代器,请锁定weak_ptr
并搜索结果的shared_ptr
。 - Kent