Home > front end >  Why does a null but non-empty std::shared_ptr fail an if() statement?
Why does a null but non-empty std::shared_ptr fail an if() statement?

Time:04-15

To recap:

  • A shared_ptr contains a pointer to the managed object.
  • A shared_ptr contains a reference to a control block which is shared amongst shared_ptrs.
  • In case ptr to managed object = nullptr -> shared_ptr is considered null
  • In case ptr to control block = nullptr -> shared_ptr is considered empty

What's interesting is you can create null but non-empty shared_pts by casting nullptr to reference type like so (example borrowed from another thread.

#include <memory>
#include <iostream>

int main()
{
    std::cout << "std::shared_ptr<int> ptr1(static_cast<int*>(nullptr))" << std::endl;
    {
        std::shared_ptr<int> ptr1(static_cast<int*>(nullptr));
        std::cout << "\tuse count before copying ptr: " << ptr1.use_count() << std::endl;
        std::shared_ptr<int> ptr2 = ptr1;
        std::cout << "\tuse count  after copying ptr: " << ptr1.use_count() << std::endl;        
        std::cout << "\tptr1 is " << (ptr1 ? "not null" : "null") << std::endl;
    }
    std::cout << std::endl;
}

This will output the following:

std::shared_ptr<int> ptr1(static_cast<int*>(nullptr))
    use count before copying ptr: 1
    use count  after copying ptr: 2
    ptr1 is null

As you can see the shared_ptr fails the if()-statement and is considered null. But how is that possible when obviously there must be a non-null pointer to the task control block inside the shared_ptr object? I would have thought that only objects which equate to 0 memory (all fields set to 0) are considered null.

CodePudding user response:

The use count is a property of a shared_ptr. But asking about that property is different from asking whether the pointer points to a live T. That question is purely about the pointer the shared_ptr instance holds, and that's the question explicit operator bool answers.

Indeed, the pointer being held by a shared_ptr<T> can be entirely independent of the object being managed. You can associate a managed state object with basically any pointer you like. Accessing the shared_ptr<T> will access the T it currently stores, but this does not have to be a pointer to the object being managed. So trying to combine the two questions just doesn't make sense.

CodePudding user response:

I would have thought that only objects which equate to 0 memory (all fields set to 0) are considered null

There us no such thing as "null object" in C .

A built-in pointer (including a pointer-to-member) can be a null pointer. Null pointers do not have to be represented with all zero bits. A character can be a null character. A number can be zero (not "null"). There are few other null things in C , like null statements and null preprocessor directives, but those are not objects.

shared_ptr objects are not called "null pointers" by the C standard (they are not pointers, only built-in pointers are pointers). The standard only says things like r.get() == nullptr to express the idea of a shared_ptr not pointing to an object. Colloquially, in this case we may say that "the shared pointer is null". This usage is non-standard, and it has nothing to do with zero or non-zero bits inside a shared_ptr representation.

A shared_ptr is convertible to bool and this conversion enables things like r ? .. : ... and if (r) .... The conversion operator returns exactly get() == nullptr and not anything about zero or non-zero bits inside a shared_ptr representation.

  • Related