#новичкам
Если вы хотите как-то по-особенному контролировать время жизни объекта, то с функциями std::make_unique и std::make_shared у вас могут быть проблемы.
struct Type {
static std::unique_ptr<Type> Create() {
return std::make_unique<Type>();
}
private:
Type() = default;
};
int main()
{
auto obj = Type::Create();
}Этот код не скомпилируется. Все потому что для класса std::make_unique - это внешний код и ей нужен публичный конструктор для работы.
Это можно обойти, просто использовав явный вызов new:
struct Type {
static std::unique_ptr<Type> Create() {
return std::unique_ptr<Type>(new Type);
}
private:
Type() = default;
};
int main()
{
auto obj = Type::Create();
}Но это же явный вызов new! Из всех утюгов твердят, что сырые указатели - наши враги и с ними надо вести ожесточенную войну!
Есть один вариант, как этого можно избежать(если сырые указатели вызывают у вас диарею). Давайте сделаем публичный конструктор, но сделаем один из его параметров приватным типом класса. Сделаем у подтипа приватный конструктор и добавим Type в друзья. Тогда создавать объект по-прежнему можно будет только с помощью фабричного статического метода, но разблокируется возможность использовать std::make_unique:
class Type {
class PrivateKey { // private struct of Type
PrivateKey() = default;
friend Type;
};
public:
Type(PrivateKey) {}
static std::unique_ptr<Type> Create() {
return std::make_unique<Type>(PrivateKey{});
}
};
int main() {
auto obj = Type::Create(); // OK
auto obj2 = Type(PrivateKey{}); // ERROR: PrivateKey is private
}По сути, это та же идиома passkey из этого поста. Только здесь она раскрывается с еще одной стороны.
Спасибо комментаторам из поста про запрет создания объектов на стеке за идею для публикации!
Know your enemies. Stay cool.
#cppcore #design #memory