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.
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_ptr
s 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.