2015-06-14 217 views
2

所以我有一個std::vector<std::shared_ptr<T>> myListOfT;,我有一個std::weak_ptr<T> ptrToOneT;是從用來填充該容器的指針之一創建的(比如我在回調函數中使用它)。該容器上的std::find和我的weak_ptr會給我一個原始shared_ptr的迭代器(如果集合中存在這樣的一個)?它在標準的某個地方有保證還是依賴於這個實現?對象std :: shared_ptr是否可以通過它的std :: weak_ptr找到?

+0

簡短回答是肯定的,但在進行比較之前,您可能需要將'get()'返回的值轉換爲絕對基址指針。 –

+4

用'weak_ptr :: lock()'獲得'shared_ptr',然後將它傳遞給'std :: find'。你會發現一些指向同一個對象的指針。 –

+0

另外,通過鎖定,可以防止weak_ptr指向的對象被刪除,例如,引用計數變爲零。在另一個線程中。 –

回答

1

std::weak_ptr::lock()是你如何「促進」一個weak_ptrshared_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

+1

不能使用'std :: owner_less'嗎? – dyp

+0

@dyp我不確定。我從來沒有聽說過。 – Barry

+0

似乎是這樣的:http://stackoverflow.com/a/12302176/ – dyp

3

我們可以逃脫使用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); 

拉姆達可以通過結合表達代替,例如:

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。但是,​​在這種情況下是正確的。因此,優化後的版本不會在該範圍內找到空的共享指針。


應該在範圍內找到空的共享指針嗎?

考慮:

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


有關其他背景,請參閱:

+1

+1,很好找,但我認爲如果weak_ptr過期了,你可以繞過整個搜索?這一個會擺脫O(1)而不是O(N)。 – davidhigh

+2

@davidhigh有趣。儘管至少在小範圍內測量它可能是值得的,因爲我猜「過期」需要原子讀取。 – dyp

+1

據我瞭解你的方法,只有當你想從搜索(?)中刪除'nullptr == nullptr'命中時,我的評論纔有效 - 至少我會直覺地想要...其他人可能不會,以及那麼這顯然是有利的。 – davidhigh

1

我在自己的代碼前幾天也有類似的問題。根據我的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; 
    } 

注意FOT這個應用程序,我會考慮的nullptr等效與本身,即nullptr == nullptrtrue,因爲不需要。因此,我從謂詞(也從第一個代碼塊中的搜索中)排除了這種情況。

編輯:只是認爲owner_lock解決方案@dyp,這是有利的,如果它只是關於搜索。

相關問題