You can write a wrapper around std::shared_ptr that only allows creation with a null value:
#include <memory> #include <cassert> template <typename T> class shared_reference { std::shared_ptr<T> m_ptr; shared_reference(T* value) :m_ptr(value) { assert(value != nullptr); } public: shared_reference(const shared_reference&) = default; shared_reference(shared_reference&&) = default; ~shared_reference() = default; T* operator->() { return m_ptr.get(); } const T* operator->() const { return m_ptr.get(); } T& operator*() { return *m_ptr.get(); } const T& operator*() const { return *m_ptr.get(); } template <typename XT, typename...XTypes> friend shared_reference<XT> make_shared_reference(XTypes&&...args); }; template <typename T, typename...Types> shared_reference<T> make_shared_reference(Types&&...args) { return shared_reference<T>(new T(std::forward<Types>(args)...)); }
Note that operator= is not yet available. You must definitely add it.
You can use it as follows:
#include <iostream> using std::cout; using std::endl; struct test { int m_x; test(int x) :m_x(x) { cout << "test("<<m_x<<")" << endl; } test(const test& t) :m_x(t.m_x) { cout << "test(const test& " << m_x << ")" << endl; } test(test&& t) :m_x(std::move(t.m_x)) { cout << "test(test&& " << m_x << ")" << endl; } test& operator=(int x) { m_x = x; cout << "test::operator=(" << m_x << ")" << endl; return *this;} test& operator=(const test& t) { m_x = t.m_x; cout << "test::operator=(const test& " << m_x << ")" << endl; return *this;} test& operator=(test&& t) { m_x = std::move(t.m_x); cout << "test::operator=(test&& " << m_x << ")" << endl; return *this;} ~test() { cout << "~test(" << m_x << ")" << endl; } };
Output:
test(1) test(5) test::operator=(test&& 5) ~test(5) ~test(5) test(2) test(test&& 2) ~test(2) ~test(2)
Example for Coliru
I hope I have not forgotten anything that could lead to undefined behavior.
source share