2017-01-28 5 views
-2
Foo(Foo&& other) { 
    this->bar = other.bar; 
    other.bar = nullptr; 
} 

Foo(Foo* other) { 
    this->bar = other->bar; 
    other->bar = nullptr; 
} 

Эти два, кажется, просто делают то же самое. Итак, почему рекомендуется использовать конструктор перемещения? Какие преимущества он дает?В чем преимущество использования конструктора перемещения против передачи указателя?

+2

Ну, для начала вы не можете взять адрес rvalue ... – Brian

+2

Преимущества заключается в том, что конструктор перемещения будет автоматически использоваться в соответствующих контекстах перемещения/копирования. Конструктора «указателя» не будет. – AnT

+0

Кроме того, ссылка не может быть нулевой, но может быть указатель, поэтому вам нужно будет явно проверить это условие перед заменой. –

ответ

4

Причины использования надлежащего конструктор перемещения много:

  1. конвенции. Рассмотрим следующий код:

    Foo foo; 
    Foo bar(std::move(foo)); 
    

    Если вы видите, что код, это обильно ясно, что вы пытаетесь сделать: вы двигаетесь foo в bar. В отличие от этого:

    Foo foo; 
    Foo bar(&foo); 
    

    Что это значит? Сохраняет ли указатель на другом Foo? Есть Foo какой-то тип связанного списка узлов? Вы должны найти его в документации для конструктора указателей Foo.

  2. Вы не можете получить указатель на prvalues. Foo bar(Foo{}) будет (pre-C++ 17) создать временное значение prvalue, а затем перейти от него к bar (перемещение может быть отменено до C++ 17). Но вы не можете этого сделать: Foo bar(&Foo{}).

  3. Вы получаете автоматическое движение от вещей, где это имеет смысл. C++ 17, обобщенная элизии делает многие из этих автоматических движений уходят, но есть некоторые, которые остаются:

    Foo function() 
    { 
        Foo foo; 
        //Do stuff 
        return foo; 
    } 
    

    Это будет двигаться от foo без вызова std::move. Причина в том, что foo - локальная переменная, которая вот-вот будет уничтожена. Возвращение его таким образом означает, что вполне разумно перейти от него к возвращаемому значению.

    Ваш путь потребовал бы явного написания return &foo. И это делает вещи довольно сложными с выводом типа auto. Такая функция выводит Foo*, что означает, что вы только что вернули висячий указатель. Если вы делаете return foo;, он выводит Foo prvalue с автоматическим перемещением (которое может быть отменено).

  4. Нет необходимости в nullptr проверках. Если вы возьмете Foo*, возможно, кто-то передаст нулевой указатель. В то время как со ссылкой это гораздо более маловероятно (и они уже вызывают UB).

Если мы хотим двигаться поддержку с существующими конструкциями языка, мы бы просто использовали не- const ссылка означает «движение», а не указатель. Давая ему свой синтаксис, дайте понять, когда мы что-то двигаем, а когда нет.

 Смежные вопросы

  • Нет связанных вопросов^_^