How to check if weak_ptr is empty (non-assigned)?

前端 未结 3 1525
天命终不由人
天命终不由人 2021-02-18 17:29

Is there a way to distinguish between an assigned (possibly expired) weak_ptr and a non-assigned one.

weak_ptr w1;
weak_ptr w2 = ...;


        
相关标签:
3条回答
  • 2021-02-18 18:15

    Using std::weak_ptr::expired()

    #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();
    }
    

    Output

    pointer  is expired
    pointer is valid
    pointer  is expired
    Program ended with exit code: 0
    
    0 讨论(0)
  • 2021-02-18 18:16

    You can use two calls to owner_before to check equality with a default constructed (empty) weak pointer:

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

    This will only return true if w{} "==" weak, where "==" compares owner, and according to en.cppreference.com:

    The order is such that two smart pointers compare equivalent only if they are both empty or if they both own the same object, even if the values of the pointers obtained by get() are different (e.g. because they point at different subobjects within the same object).

    Since the default constructor constructs an empty weak pointer, this can only return true if weak is also empty. This will not return true if weak has expired.

    Looking at the generated assembly (with optimization), this seems pretty optimized:

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

    ... compared to checking 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
    

    ... or returning !weak.lock() (~80 lines of assembly).

    0 讨论(0)
  • 2021-02-18 18:24

    You could try to create a shared pointer that accepts a weak pointer as a parameter and raises a std::bad_weak_ptr exception if a weak pointer is expired (or not assigned as in your case):

    #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';
        }
    }
    
    0 讨论(0)
提交回复
热议问题