Подтвердить что ты не робот

Почему unique_ptr <T> (T *) явно?

Следующие функции не компилируются:

std::unique_ptr<int> foo()
{
    int* answer = new int(42);
    return answer;
}

std::unique_ptr<int> bar()
{
    return new int(42);
}

Я нахожу это немного неудобным. В чем заключалось явное выражение std::unique_ptr<T>(T*)?

4b9b3361

Ответ 1

Вы не хотите, чтобы управляемый указатель захватил владение необработанным указателем неявно, так как это может привести к поведению undefined. Рассмотрим функцию void f( int * ); и вызов int * p = new int(5); f(p); delete p;. Теперь представьте, что кто-то рефакторирует f, чтобы взять управляемый указатель (любого типа) и что неявные преобразования были разрешены: void f( std::unique_ptr<int> p );, если неявное преобразование разрешено, ваш код будет компилироваться, но вызывать поведение undefined.

Таким же образом учтите, что указатель может быть даже не динамически распределен: int x = 5; f( &x );...

Приобретение собственности является достаточно важной операцией, что лучше иметь ее явным: программист (а не компилятор) знает, следует ли управлять ресурсом с помощью интеллектуального указателя или нет.

Ответ 2

Короткий ответ:

Явный конструктор затрудняет запись опасного кода. Другими словами, неявный конструктор помогает вам легче писать опасный код.

Длинный ответ:

Если конструктор неявный, вы можете легко написать такой код:

void f(std::unique_ptr<int> param)
{
     //code

} //param will be destructed here, i.e when it goes out of scope
  //the pointer which it manages will be destructed as well. 

Теперь посмотрите на опасную часть:

int *ptr = new int;

f(ptr); 
//note that calling f is allowed if it is allowed:
//std::unique_ptr<int> test = new int;
//it is as if ptr is assigned to the parameter:
//std::unique_ptr<int> test = ptr;

//DANGER
*ptr = 10; //undefined behavior because ptr has been deleted by the unique_ptr!

Прочитайте комментарии. Он объясняет каждую часть фрагмента кода выше.

При вызове f() с необработанным указателем программист может не понимать, что тип параметра f() равен std::unique_ptr, который будет владеть указателем и будет delete, когда он выходит из области видимости. Программист, с другой стороны, может использовать его, и delete он даже не понимает, что он уже удален! Все это происходит из-за неявного преобразования из исходного указателя в std::unique_ptr.

Обратите внимание, что std::shared_ptr имеет конструктор explicit по той же причине.