Shared_ptr, which cannot be null?

Using std::shared_ptr expresses ownership and optionality (with the ability to be null).

I am in situations where I want to express joint ownership only in my code, and have no way. When using shared_ptr as a function parameter, I must let the function verify that it is not null in order to be consistent / safe.

Passing a link, and not, of course, is an option in many cases, but sometimes I would also like to transfer ownership, as is possible with shared_ptr .

Is there a class for replacing shared_ptr without the ability to be null, any agreement to solve this problem, or is my question not making much sense?

+5
source share
2 answers

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; } }; #include <string> int main() { { auto ref = make_shared_reference<test>(1); auto ref2 = ref; *ref2 = test(5); } { test o(2); auto ref = make_shared_reference<test>(std::move(o)); } //Invalid case //{ // test& a = *(test*)nullptr; // auto ref = make_shared_reference<test>(a); //} } 

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.

+2
source

You are requesting a not_null wrapper not_null . Fortunately, your problem has already been considered by experts from the C ++ guideline , and there are already implementation examples - sort of one . Find the class template not_null .

+3
source

Source: https://habr.com/ru/post/1263618/


All Articles