Функция перемещения в эмуляции unique_ptr C ++ 03 - PullRequest
7 голосов
/ 09 декабря 2011

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

Вопросы:

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

    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> в качестве параметра.Почему этот не поднят автоматически?

1 Ответ

3 голосов
/ 10 декабря 2011

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

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

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

...