shared_ptr, который не может быть нулевым?

Используя std::shared_ptr выражает совместную собственность и возможность (с возможностью быть нулевым).

Я нахожусь в ситуациях, когда я хочу выразить совместное владение только в моем коде, а не опционально. При использовании shared_ptr в качестве параметра функции я должен позволить функции проверить, что она не является нулевой, чтобы быть последовательной / безопасной.

Передача ссылки, конечно, является вариантом во многих случаях, но я иногда хотел бы также передать право собственности, как это возможно с shared_ptr,

Есть ли класс для замены shared_ptr без возможности быть нулевым, какое-то соглашение для решения этой проблемы, или мой вопрос не имеет большого смысла?

7

Решение

Вы могли бы написать обертку вокруг std::shared_ptr это позволяет только создание из ненулевого:

#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)...));
}

Обратите внимание, что operator= отсутствует еще. Вы должны обязательно добавить это.

Вы можете использовать это так:

#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);
//}
}

Выход:

test(1)
test(5)
test::operator=(test&& 5)
~test(5)
~test(5)
test(2)
test(test&& 2)
~test(2)
~test(2)

Пример на Колиру

Я надеюсь, что не забыл ничего, что могло бы привести к неопределенному поведению.

4

Другие решения

Вы просите not_null класс обертки. К счастью, ваша проблема уже решена экспертами C ++ директива и уже есть примеры реализации — как это один. Ищи not_null шаблон класса.

3

По вопросам рекламы [email protected]