Как заставить экземпляр класса только умные указатели?

Я работал над способом предотвращения использования пользователем класса без умных указателей. Таким образом, вынуждая их выделять кучу объектов и управлять ими с помощью интеллектуальных указателей.
Чтобы получить такой результат, я попробовал следующее:

#include <memory>
class A
{
private :
~A {}
// To force use of A only with std::unique_ptr
friend std::default_delete<A>;
};

Это работает очень хорошо, если вы хотите, чтобы пользователи вашего класса могли манипулировать экземпляром вашего класса через std::unique_ptr, Но это не работает для std::shared_ptr, Поэтому я хотел бы знать, есть ли у вас какие-либо идеи, чтобы получить такое поведение. Единственное решение, которое я нашел, это сделать следующее (используя friend std::allocator_traits<A>; было недостаточно)

#include <memory>
class A
{
private :
~A {}
// For std::shared_ptr use with g++
friend __gnu_cxx::new_allocator<A>;
};

Но это решение не переносимо. Может быть, я делаю это неправильно.

12

Решение

Создайте фабричную функцию друга, которая возвращает std::unique_ptr<A>и сделать ваш класс не имеет доступных конструкторов. Но сделайте деструктор доступным:

#include <memory>

class A;

template <class ...Args>
std::unique_ptr<A> make_A(Args&& ...args);

class A
{
public:
~A() = default;
private :
A() = default;
A(const A&) = delete;
A& operator=(const A&) = delete;

template <class ...Args>
friend std::unique_ptr<A> make_A(Args&& ...args)
{
return std::unique_ptr<A>(new A(std::forward<Args>(args)...));
}
};

Теперь ваши клиенты могут получить unique_ptr<A>:

std::unique_ptr<A> p1 = make_A();

Но ваши клиенты могут так же легко получить shared_ptr<A>:

std::shared_ptr<A> p2 = make_A();

Так как std::shared_ptr может быть построен из std::unique_ptr, И если у вас есть какие-либо умные указатели, написанные пользователем, все, что им нужно сделать для взаимодействия с вашей системой, это создать конструктор, который принимает std::unique_ptr, как std::shared_ptr имеет, и это очень легко сделать:

template <class T>
class my_smart_ptr
{
T* ptr_;
public:
my_smart_ptr(std::unique_ptr<T> p)
: ptr_(p.release())
{
}
// ...
};
17

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

Так как нет общего термина «умный указатель», то, что вы хотите, не представляется возможным.

Что вы можете сделать, так это поддержать некоторый известный набор умных указателей. Обычное решение начинается с вашего, делая ctor или dtor приватными, и добавляет фабричные функции. Это может вернуть экземпляр, упакованный с вашими желаемыми умными указателями. Если вы просто хотите поддерживать unique_ptr и shared_ptr, это означает две заводские функции, вряд ли слишком много. (обратите внимание, что эти указатели позволяют вывозить необработанный указатель через простой интерфейс, поэтому контроль не является полным).

0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector