簡體   English   中英

對象std :: shared_ptr是否可以通過std :: weak_ptr找到?

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

所以我有一個std::vector<std::shared_ptr<T>> myListOfT; 我有一個std::weak_ptr<T> ptrToOneT; 這是從用於填充該容器的指針之一創建的(假設我在回調函數中有它)。 請問std::find在那個容器上,我的weak_ptr給我一個原始shared_ptr的迭代器(如果這個存在於集合中)? 它是否在標准的某個地方得到保證還是依賴於此實現?

我們可以逃脫鎖定weak_ptr使用std::weak_ptr::owner_before 我將使用比必要更詳細的解決方案,並引入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可以用bind-expression替換,例如:

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為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


有關其他上下文,請參閱:

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 == nullptrtrue ,這是不需要的。 因此,我從謂詞(以及第一個代碼塊中的搜索)中排除了這種情況。

編輯:剛剛考慮owner_lock解決方案,如果只是搜索,這是有利的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM