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++?
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With