2017-08-04 511 views
8

有沒有辦法區分分配的(可能過期的)weak_ptr和未分配的weak_ptr。如何檢查weak_ptr是否爲空(未分配)?

weak_ptr<int> w1; 
weak_ptr<int> w2 = ...; 

我瞭解以下檢查是否爲非轉讓或過期,但是是否存在僅用於非轉讓的(便宜?)檢查?

if (!w.lock()) { /* either not assigned or expired */ } 
+0

您可以使用'過期',但AFAIK沒有辦法區分。 – NathanOliver

+0

模擬['std :: optional'](http://en.cppreference.com/w/cpp/utility/optional)的東西可能是 – AndyG

回答

12

您可以使用兩種調用owner_before檢查與構建一個默認的平等(空)弱指針:

template <typename T> 
bool is_uninitialized(std::weak_ptr<T> const& weak) { 
    using wt = std::weak_ptr<T>; 
    return !weak.owner_before(wt{}) && !wt{}.owner_before(weak); 
} 

這隻會返回true如果w{} "==" weak,其中"=="比較所有者,並根據en.cppreference.com

的順序是這樣的,兩個智能指針比較只相當於如果它們都是空的,或者如果他們都擁有相同的對象,即使get()獲得的指針的值不同(例如,因爲它們指向同一對象內的不同子對象)。

由於默認構造函數構造弱指針,這隻能返回true如果weak。這將返回true如果weak已過期。

看着生成的彙編(最優化),這似乎是相當優化:

bool is_uninitialized<int>(std::weak_ptr<int> const&): 
     cmp  QWORD PTR [rdi+8], 0 
     sete al 
     ret 

...相比,檢查weak.expired()

bool check_expired(std::weak_ptr<int> const&): 
     mov  rdx, QWORD PTR [rdi+8] 
     mov  eax, 1 
     test rdx, rdx 
     je  .L41 
     mov  eax, DWORD PTR [rdx+8] 
     test eax, eax 
     sete al 
.L41: 
     rep ret 

...或returning !weak.lock()(〜80線的組裝)。

+0

真棒解決方案+驗證。 – Zuza

+0

的確很好的答案。一個相當晦澀的竅門,但它至少可以工作。 +1 – skypjack

0

使用的std :: weak_ptr的::過期()

#include <iostream> 
#include <memory> 

//declare a weak pointer 
std::weak_ptr<int> gw; 

void f() 
{ 
    //check if expired 
    if (!gw.expired()) { 
     std::cout << "pointer is valid\n"; 
    } 
    else { 
     std::cout << "pointer is expired\n"; 
    } 
} 

int main() 
{ 
    f(); 
    { 
     auto cre = std::make_shared<int>(89); 
     gw = cre; 
     f(); 
    } 

    f(); 
} 

輸出

pointer is expired 
pointer is valid 
pointer is expired 
Program ended with exit code: 0 
+0

'stl :: expired'不是問題。你的意思是['std :: weak_ptr :: expired()'](http://en.cppreference.com/w/cpp/memory/weak_ptr/expired)。 –

+0

我的看法是,這比在分配對象的情況下檢查nullptr要慢。 – Zuza

0

你可以嘗試創建一個共享的指針,它接受一個弱指針作爲參數,並提出了一個std::bad_weak_ptr異常,如果一個弱指針已過期(或在您的情況下未分配的):

#include <memory> 
#include <iostream> 
int main(){ 
    // with an assigned pointer 
    std::shared_ptr<int> p1(new int(42)); 
    std::weak_ptr<int> w1(p1); 
    try { 
     std::shared_ptr<int> p2(w1); 
    } 
    catch (const std::bad_weak_ptr& e) { 
     std::cout << e.what() << '\n'; 
    } 
    // with a non assigned pointer 
    std::shared_ptr<int> p2(new int(42)); 
    std::weak_ptr<int> w2; 
    try { 
     std::shared_ptr<int> p2(w2); // raises an exception 
    } 
    catch (const std::bad_weak_ptr& e) { 
     std::cout << "Ptr 2: " << e.what() << '\n'; 
    } 
} 
+1

這確實解決了我的問題,但在簡單檢查的預期路徑中引發異常似乎很糟糕。 – Zuza