Функция перемещения в эмуляции unique_ptr C++03

Я пытаюсь понять, как реализована эмуляция unique_ptr в C++03. unique_ptr очень похож на std::auto_ptr, но безопаснее. Он выдает ошибки компилятора в тех случаях, когда auto_ptr передал бы право собственности неявно (т. е. молча). Например, простое задание. Функция move является ключом к безопасности эмулируемого unique_ptr.

Вопросы:

  1. Почему существует три функции перемещения?
  2. Третья функция перемещения, которая принимает ссылку и превращает ее в rvalue, реализована (упрощена) следующим образом.

    T move(T &t) { 
      return T(detail_unique_ptr::rv<T>(t)); 
    }
    

В приведенном выше коде явное преобразование в T кажется ненужным. На самом деле Visual Studio 2010 прекрасно работает без явного преобразования в T.

T move(T &t) {
  return detail_unique_ptr::rv<T>(t);
}

g++, clang, Comeau, однако, второй вариант не нравится. Эти компиляторы жалуются, что нет конструктора для unique_ptr<T>, который принимает detail_unique_ptr::rv<T> в качестве параметра. Почему это? unique_ptr уже определяет (неявный) конструктор, который принимает detail_unique_ptr::rv<T> в качестве параметра. Почему этот не подхватывается автоматически?


person Sumant    schedule 09.12.2011    source источник
comment
Пейджинг @HowardHinnant, автор указанного кода...   -  person ildjarn    schedule 09.12.2011


Ответы (1)


Причина в том, что вы не можете инициализировать unique_ptr с помощью другого unique_ptr без выполнения определяемого пользователем преобразования (в rv путем передачи rvalue принимающему rv конструктору unique_ptr). Однако, если явно не вызывать ctor unique_ptr (как в unique_ptr(...)), вы выполняете инициализацию копирования, которая в вашем случае сначала успешно создает временное значение rvalue unique_ptr, но затем не может скопировать это временное значение в целевой объект возвращаемого значения, потому что в этой копии никакие пользовательские преобразования не разрешены (это также известно как принципиальное правило «никаких двух пользовательских преобразований в инициализации»). Msvc позволяет копии использовать ctor с неконстантной ссылкой unique_ptr, что является нестандартным.

При выполнении инициализации копированием класса из объекта того же класса такой двухэтапной инициализации не существует. Исходный объект просто передается неявным конструкторам unique_ptr, которые преобразуют его в rv с помощью конструктора, принимающего rv, и таким образом успешно создают целевой объект возвращаемого значения.

По той же причине нет неявного преобразования unique_ptr<Derived> в unique_ptr<Base>. На первом этапе будет успешно создан unique_ptr<Base>, но затем при копировании этого временного объекта в целевой объект unique_ptr<Base> ограничение, заключающееся в том, что никакие пользовательские преобразования не могут использоваться, препятствует успеху.

person Johannes Schaub - litb    schedule 09.12.2011
comment
Спасибо литб! Не могли бы вы рассказать мне, зачем нужны еще две функции перемещения? - person Sumant; 11.12.2011
comment
Почему бы не вызвать unique_ptr<T>(detail_unique_ptr::rv<T>) напрямую, чтобы сделать копию, не требующую определяемого пользователем преобразования? - person spockwang; 18.12.2015