简体   繁体   English

对象std :: shared_ptr是否可以通过std :: weak_ptr找到?

[英]Is object std::shared_ptr findable by its std::weak_ptr?

So I have a std::vector<std::shared_ptr<T>> myListOfT; 所以我有一个std::vector<std::shared_ptr<T>> myListOfT; and I have a std::weak_ptr<T> ptrToOneT; 我有一个std::weak_ptr<T> ptrToOneT; that was created from one of the pointers used to fill that container (say I have it inside a callback function). 这是从用于填充该容器的指针之一创建的(假设我在回调函数中有它)。 Will std::find on that container and my weak_ptr give me an iterator to the original shared_ptr (if such one exists in the collection)? 请问std::find在那个容器上,我的weak_ptr给我一个原始shared_ptr的迭代器(如果这个存在于集合中)? Is it guaranteed somewhere in standard or is this implementation dependent? 它是否在标准的某个地方得到保证还是依赖于此实现?

We can get away without locking the weak_ptr by using std::weak_ptr::owner_before . 我们可以逃脱锁定weak_ptr使用std::weak_ptr::owner_before I'll use a slightly more verbose solution than necessary and introduce owner_equal , which is the counterpart to std::owner_less : 我将使用比必要更详细的解决方案,并引入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); }
};

With this function object type, we can customize std::find_if : 使用此函数对象类型,我们可以自定义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);

The lambda can be replaced by a bind-expression such as: lambda可以用bind-expression替换,例如:

auto pred = std::bind(owner_equal<T>{}, std::cref(ptrToOneT),
                      std::placeholders::_1);

@davidhigh suggested an optimization: @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);
    }
}

(not tested) (未测试)

This also slightly changes the behaviour: If the weak_ptr is "empty", eg having been created from an empty shared_ptr or via the default ctor, it will compare equal to any empty shared_ptr via owner_equal . 这也稍微改变了行为:如果weak_ptr是“空”,例如,已经从空的shared_ptr或通过默认的ctor创建,它将通过owner_equal比较任何空的shared_ptr However, weak_ptr::expired is true in that case. 但是,在这种情况下, weak_ptr::expired为true。 Therefore, the optimized version will not find empty shared pointers in the range. 因此,优化版本将不会在该范围内找到空的共享指针。


Should empty shared pointers be found in the range? 应该在范围内找到空的共享指针吗?

Consider: 考虑:

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);

Empty shared pointers are equal . 空共享指针是相等的 Therefore, if you allow finding empty shared pointers, r_pos != pos && r != end(myListOfT) is possible. 因此,如果您允许查找空的共享指针,则可以使用r_pos != pos && r != end(myListOfT) For example, the first version of the algorithm in this answer yields r_pos == 0 . 例如,此答案中的第一个算法版本产生r_pos == 0


For additional context, see: 有关其他上下文,请参阅:

std::weak_ptr::lock() is how you "promote" a weak_ptr to a shared_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
}

If lock() succeeds, then you have a normal std::shared_ptr<T> that you can use to find() like you would any other object in a container. 如果lock()成功,那么你可以使用正常的std::shared_ptr<T>find()就像容器中的任何其他对象一样。 Though you may not need to find() it since you already have it (unless you want to erase() it or something). 虽然你可能不需要find()它,因为你已经拥有它(除非你想erase()它或什么)。

Side-note, with shared_ptr , it's not really meaningful to refer to the "original shared_ptr " 侧注,使用shared_ptr ,引用“原始shared_ptr ”并没有多大意义。

I had a similar problem a few days ago in my own code. 我几天前在自己的代码中遇到过类似的问题。 According to my SO-research, it is possible to do what you asked for. 根据我的SO研究,你可以做你想要的。 Lock the weak-pointer and if the shared-pointer is not-expired, then use std::find 锁定弱指针,如果共享指针未过期,则使用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;
        }
    }
}

Note that the C++ standard itself is not that relevant here -- the heart of the comparison of the shared-pointers is a comparison of the contained raw pointers, ie addresses in memory are compared. 请注意,C ++标准本身并不重要 - 共享指针比较的核心是所包含的原始指针的比较,即比较内存中的地址。

Alternatively, if you have a vector of weak-pointers, you could use std::find_if with a predicate that locks on the fly: 或者,如果你有一个弱指针向量,你可以使用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;
    }

Note that fot this application, I would consider the equivalence of nullptr with itself, ie that nullptr == nullptr is true , as unwanted. 请注意,在这个应用程序中,我会考虑nullptr与其自身的等价性,即nullptr == nullptrtrue ,这是不需要的。 Thus I excluded this case from the predicate (and also from the search in the first code block). 因此,我从谓词(以及第一个代码块中的搜索)中排除了这种情况。

EDIT: just considered the owner_lock solution by @dyp, which is advantageous if it is just about the search. 编辑:刚刚考虑owner_lock解决方案,如果只是搜索,这是有利的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用std :: weak_ptr和std :: shared_ptr进行阴影 - Using std::weak_ptr with std::shared_ptr for shadowing std :: shared_ptr,std :: weak_ptr和控制块 - std::shared_ptr, std::weak_ptr and control block std :: weak_ptr:lock或shared_ptr构造函数? - std::weak_ptr: lock or shared_ptr constructor? 使用 std::shared_ptr/weak_ptr 的简化观察者模式 - simplfied observer pattern with std::shared_ptr/weak_ptr 将std :: shared_ptr的容器(std :: vector)过滤到std :: weak_ptr的容器 - Filtering a container ( std::vector ) of std::shared_ptr to a container of std::weak_ptr std::weak_ptr 和相应的 std::shared_ptr 之间是否存在数据竞争? - Is there any data race between std::weak_ptr and corresponding std::shared_ptr? 在信号处理程序中使用`std :: shared_ptr`和`std :: weak_ptr`是否安全? - Is it safe to use `std::shared_ptr` and `std::weak_ptr` in a signal handler? 为什么 lock() function 必须与 std::weak_ptr 一起使用才能安全地提取 std::shared_ptr? - Why must the lock() function be used with a std::weak_ptr to safely extract the std::shared_ptr? 没有可行的将std :: weak_ptr转换为std :: shared_ptr的方法调用 - No viable conversion std::weak_ptr to std::shared_ptr for method call 用 std::shared_ptr 和 std::weak_ptr 替换引用存储 - Replace references storage with std::shared_ptr and std::weak_ptr
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM