Search code examples
c++shared-ptrsmart-pointersweak-ptr

How to initialize object's manager w/o initializing object in shared_ptr?


I want to use smart pointers in this way:

using namespace std;

shared_ptr<string> foo;
weak_ptr<string> bar (foo);
foo = make_shared<string>("some string");
cout << *bar.lock(); // SIGSEGV

The clue is how to initialize shared_ptr's object manager without construction the object (string in this case). Is it even possible? I could use default ctor of the object and later use copy/move assignment. But may some more elegant solution exist?

It is worth for me that the object won't be initialized - it would be a lie in logic if I would initialize the shared_ptr with empty value.


Solution

  • I solved my problem. The core of this idea is to use nested pointers: shared_ptr<unique_ptr<MYTYPE>>. In my case I created a wrapping template:

    template<typename T>
    class LazyInitializator : public std::unique_ptr<T> {
    public:
        LazyInitializator() : std::unique_ptr<T>() {} // this ctor offers lazy initialization
        LazyInitializator(const T& val) : std::unique_ptr<T> (std::make_unique<T>(val)) {} // for normal construction
        LazyInitializator& operator= (const T& val) { 
            if (!std::unique_ptr<T>::operator bool()) // if object wasn't constructed
                std::unique_ptr<T>::operator= (std::make_unique<T>(val)); // construct it
            **this = val; // use assingment op provided by T - no unneccessary mem allocation
            return *this;
        }
    };
    

    Thanks to it I can use shared_ptrs in easier way. I can do sth like this:

    using namespace std;
    
    shared_ptr<LazyInitializator<string>> foo = make_shared<LazyInitializator<string>>();
    weak_ptr<LazyInitializator<string>> bar (foo);
    *foo = "some string";
    cout << **bar.lock();
    

    Yes, I know, looks a bit tricky, but it is the best solution for me now.