Каковы причины, по которым конструктор std::unique ptr из T* является явным?
Поскольку 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
не может быть передано по значению, это не должно быть проблемой, не так ли?
2 ответа:
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-читать здесь)