如何测试 shared_ptr 是空的还是什么都不拥有

How to test whether a shared_ptr is empty or owns nothing

A C++ std::shared_ptr<..> 可能是 empty 也可能是 null。这两个概念都存在,并且它们等价。此外,这些情况之间的任何暗示都不总是正确的。

后一种情况很容易检测到,因为 operator bool 恰好提供了该测试。根据文档,它 "checks if *this stores a non-null pointer, i.e. whether get() != nullptr."

有没有测试前一种情况,那个东西是empty的情况?

我对此的使用非常简单。我有一个具有静态工厂方法的 class。静态工厂方法内部是 class 实例的静态本地 shared_ptr,初始化为 nullptr。对该工厂方法的第一次调用构造 class 的实例并在返回它的副本之前初始化静态本地 shared_ptr - 这由 mutex 保护。 shared_ptr 可以被任何东西持有、复制和传递,更多的副本可以通过对静态工厂的额外调用来获取,最后,当所有副本都被销毁时,shared_ptr 的删除器会销毁实例。

实例本身是使用遗留 C API 创建和销毁的,由我的 class 包装,并且,尽管这些实例旨在作为单例共享,但它们也需要清理当不再需要它们时启动 - 与单身人士不同。

目前,我正在使用空检查来决定静态本地 shared_ptr 是应该初始化还是仅仅复制。我担心此测试无法检测需要重新初始化的情况 - 例如,如果在所有先前用户放弃引用并且共享实例被删除后的某个时间某些东西试图获取实例。

或者当引用计数降为零并调用删除器时,shared_ptr 被重置为 nullptr 是真的吗?也适用于自定义删除器?

也相关:What is the difference between an empty and a null std::shared_ptr in C++?

shared_ptr 的静态实例将持有一个引用,因此该对象将始终具有一个 >= 1 的引用计数,并且在静态清理发生之前不会被删除。正如 cnettel 在评论中所说,你需要 std::weak_ptr 这里。

weak_ptr 基本上是一个 shared_ptr,它不会影响引用计数。它通过 .lock() 方法对 std::shared_ptr 进行了原子转换。得到的std::shared_ptr如果没有初始化会转成false,所以你知道要重新初始化(或者说是第一次初始化)

示例:

std::shared_ptr<Obj> instance() {
    static std::weak_ptr<Obj> instance;
    static std::mutex lock;

    std::lock_guard<std::mutex> guard(lock);

    auto result = instance.lock();
    if (!result) {
        result = std::make_shared<Obj>();
        instance = result;
    }

    return result;
}