Я работал над способом предотвращения использования пользователем класса без умных указателей. Таким образом, вынуждая их выделять кучу объектов и управлять ими с помощью интеллектуальных указателей.
Чтобы получить такой результат, я попробовал следующее:
#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>;
};
Но это решение не переносимо. Может быть, я делаю это неправильно.
Создайте фабричную функцию друга, которая возвращает 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())
{
}
// ...
};
Так как нет общего термина «умный указатель», то, что вы хотите, не представляется возможным.
Что вы можете сделать, так это поддержать некоторый известный набор умных указателей. Обычное решение начинается с вашего, делая ctor или dtor приватными, и добавляет фабричные функции. Это может вернуть экземпляр, упакованный с вашими желаемыми умными указателями. Если вы просто хотите поддерживать unique_ptr и shared_ptr, это означает две заводские функции, вряд ли слишком много. (обратите внимание, что эти указатели позволяют вывозить необработанный указатель через простой интерфейс, поэтому контроль не является полным).