Как std::unique_ptr
обеспечивает удобный способ избежать утечек памяти и обеспечить безопасность исключений; разумно передавать их, а не исходные указатели. Таким образом, можно хотеть (член) функции с подписью как
std::unique_ptr<some_type> foo(some data);
К сожалению, при реализации такой функции нельзя просто
std::unique_ptr<some_type> foo(some data)
{
return { new some_type(data) }; // error
}
но должен вместо
std::unique_ptr<some_type> foo(some data)
{
return std::move( std::unique_ptr<some_type>( new some_type(data) ) ); // awkward
}
потому что конструктор unique_ptr::unique_ptr(pointer)
является explicit
, В чем причина этого конструктора explicit
?
Одна мотивация, чтобы сделать конструкторов explicit
это для защиты от непреднамеренного неявного преобразования типов. Тем не менее, как unique_ptr
не может быть передано по значению, это не должно быть проблемой, не так ли?
unique_ptr
вступает во владение переданным указателем. Принятие владения должно быть явным — вы не хотите, чтобы какой-то указатель «волшебным образом» становился владельцем (и удалялся) каким-то классом (это было одной из проблем с устаревшими std::auto_ptr
).
например:
void fun(std::unique_ptr<X> a) { .... }
X x;
fun(&x); // BOOM, deleting object on stack, fortunately it does not compile
fun(std::unique_ptr<X>(&x)); // compiles, but it's explicit and error is clearly visible
пожалуйста, обратите внимание, что std::move
не требуется в return
оператор (специальное языковое исключение — локальные переменные как return
аргументы могут рассматриваться как «перемещенные»).
Также — в C ++ 14 вы можете использовать std::make_unique
чтобы сделать его менее неловким:
return std::make_unique<some_data>(some_data_argument1, arg2);
(его также легко можно добавить в C ++ 11 — читайте Вот)
Аргументы, принимающие уникальные ptr, не должны молча владеть указателями.
Таким образом, ctor является явным.
Чтобы вернуться, попробуйте make_unique<foo>(?)
вместо {new foo(?)}
,