Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test whether a shared_ptr is empty or owns nothing

Tags:

c++

shared-ptr

A C++ std::shared_ptr<..> may be empty and it may also be null. Both of these concepts exist and they are not equivalent. Additionally, neither implication is always true between these cases.

The latter case is trivial to detect because operator bool provides precisely that test. According to the docs, it "checks if *this stores a non-null pointer, i.e. whether get() != nullptr."

Is there a test for the former case, the case where the thing is empty?

My use for this is quite simple. I have a class that has a static factory method. Inside the static factory method is a static local shared_ptr to an instance of the class, initialised to nullptr. The first call to this factory method constructs an instance of the class and initialises the static local shared_ptr before returning a copy of it - this is guarded by a mutex. That shared_ptr may be held by anything, copied and passed about, further copies may be acquired by additional calls to the static factory and, finally, when all the copies are destructed, the shared_ptr's deleter destructs the instance.

The instance itself is created and destructed with a legacy C API, wrapped by my class, and, although these instances are intended to be shared as singletons, they also need to be cleaned up when they are no longer needed - unlike singletons.

At the moment, I am using a null-check to decide whether the static local shared_ptr should be initialised or merely copied. I fear that this test will not work to detect the case where re-initialisation is required - for example, if something tries to acquire an instance at some time after all previous users gave up their references and the shared instance was deleted.

Or is it true that shared_ptr is reset to nullptr when the reference count falls to zero and the deleter is invoked? Also for custom deleters?

Also relevant: What is the difference between an empty and a null std::shared_ptr in C++?

like image 961
Xharlie Avatar asked Feb 08 '17 09:02

Xharlie


1 Answers

The static instance of shared_ptr will hold a reference, so the object will always have a ref count >= 1, and won't be deleted until static cleanup happens. As cnettel says in the comments, you need std::weak_ptr here.

weak_ptr is basically a shared_ptr which doesn't contribute to the ref count. It has an atomic cast to std::shared_ptr via the .lock() method. The resulting std::shared_ptr will convert to false if it is not initialized, so you know to reinitialize (or intialize for the first time).

Example:

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;
}
like image 110
Joseph Ireland Avatar answered Nov 01 '22 15:11

Joseph Ireland