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

Ответ 1

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 explicit and error is clearly visible

обратите внимание, что std::move не требуется в выражении return (специальное исключение языка - локальные переменные как аргументы return могут рассматриваться как "перемещены" ).

Также - в С++ 14 вы можете использовать std::make_unique, чтобы сделать его менее неудобным:

return std::make_unique<some_data>(some_data_argument1, arg2);

(его также можно легко добавить в С++ 11 - прочитайте здесь)

Ответ 2

Аргументы, принимающие уникальный ptr, не должны молча владеть указателями.

Таким образом, ctor явно.

Чтобы вернуться, попробуйте make_unique<foo>(?) вместо {new foo(?)}.