如何检查weak_ptr是否为空(未分配)?

33

有没有一种方法可以区分已分配(可能已过期)的 weak_ptr 和未分配的 one。

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

我明白以下代码是用于查找未被赋值或过期的情况,但是否有一种(更便宜的)方法只检查未被赋值的情况?

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

你可以使用 expired,但据我所知没有办法区分它们的不同。 - NathanOliver
1
也许需要模拟 std::optional 的某些功能。 - AndyG
2个回答

44

您可以使用两个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);
}

只有当w{} "==" weak时,此代码才会返回true。其中"=="是对所有者进行比较,根据en.cppreference.com

顺序是这样的:仅当两个智能指针都为空或它们拥有相同的对象时,它们才会相等,即使通过get()获取的指针值不同(例如,因为它们指向同一对象内的不同子对象)。

由于默认构造函数构造了一个空的弱指针,因此只有当weak也是空的时,此代码才会返回true。如果weak已过期,则不会返回true

查看生成的汇编代码(经过优化后),此代码似乎很优化:

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

... 或者 返回!weak.lock()(约80行汇编代码)。


惊人的解决方案 + 验证。 - Zuza
确实是个好答案。这是一个相当晦涩的技巧,但至少它可能有效。+1 - skypjack

9

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

输出

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

stl::expired 不是一个东西。你的意思是 std::weak_ptr<T>::expired() - François Andrieux
我的信念是,如果对象被分配,那么这种方法比检查nullptr要慢。 - Zuza
这个回答有误导性,问题是要区分未初始化的 weak_ptr 和已过期的 weak_ptr,这里只是一个测试过期的代码,并不能区分。 - 8znr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接