2016-03-21 5 views
5

Это, кажется, самый встречный вопрос, который уже задан.std :: move Vs std :: forward

Whats the difference between std::move and std::forward

Но каждый ответ отличается и применяет и говорит немного разные вещи. Поэтому я смущен.

У меня есть следующая ситуация.

  • Копировать элемент в контейнер
    Копирование элемента является C++ 03, так что я понимаю, что очень хорошо.
  • Construct элемент в контейнер
    Конструкцию элемента в контейнер я считаю, использует совершенную переадресацию правильно направить аргументы через две функции конструктору T в emplaceBackInternal() (Скажите, пожалуйста, в противном случае, если я не прав).
  • Переместить товар в контейнер
    Проблема, похоже, заключается в понимании перемещения предмета в контейнер.

Кодекс:

template<typename T> 
class Container 
{ 
    std::size_t length; 
    T*   buffer; 

public: 
    void push_back(T const& value) 
    { 
     resizeIfRequired(); 
     pushBackInternal(value); 
    } 
    template<typename... Args> 
    void emplace_back(Args&&... args) 
    { 
     resizeIfRequired(); 
     emplaceBackInternal(std::forward<T>(arg)...); 
    } 
    void push_back(T&& value) 
    { 
     resizeIfRequired(); 
     // Is this forward correct or should it be move 
     moveBackInternal(std::forward<T>(value)); 
    } 
private: 
    void pushBackInternal(T const& value) 
    { 
     // Copy construct object into buffer; 
     new (buffer + length) T(value); 
     ++length; 
    } 
    template<typename... Args) 
    void emplaceBackInternal(Args&&... args) 
    { 
     // Construct object into buffer using arguments; 
     new (buffer + length) T(std::forward<T>(args)...); 
     ++length; 
    } 
    void moveBackInternal(T&& value) 
    { 
     // Move construct object into buffer; 
     // Is this forward correct or should it be move 
     new (buffer + length) T(std::forward<T>(value)); 
     ++length; 
    } 
}; 

я включаю все три здесь, чтобы сравнить три функции с ответами, представленными в ранее упомянутом ответе. Основная причина в том, что move и construct выглядят настолько похожими, что кажется, что они должны быть одинаковыми.

Answer @Potatoswatter Score 67

станд :: вперед имеет один случай использования: изгонять параметр

в шаблонных функций Согласно этому определению, я должен использовать std::move внутри push_back(T&& value) и moveBackInternal(T&& value) как Значение не является параметром шаблона для функции.

Answer @Howard Hinnant Score 38

Если Y представляет собой ссылку-значение, то результат будет именующее выражением. Если Y не является ссылкой на lvalue, результатом будет выражение r12ue (значение xvalue to exact).

По этому определению я могу использовать либо std::move, либо std::forward.

Answer @Bo Persson Score 11

станд :: вперед используется для передачи параметра, точно так, как он был передан в функцию.

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

+0

Er ... на ваш вопрос, на который не ответили связанные ответы? – Barry

+0

Er ... какой ответ правильный !. Каждый из них указывает другой результат. –

+0

Все они правильные. Двое просто говорят, что намерение 'std :: forward' предназначено для пересылки ссылок, а третий дополнительно тратит некоторое время на объяснение того, что такое' std :: forward'. – Barry

ответ

5

В этом случае:

void push_back(T&& value) 
{ 
    resizeIfRequired(); 
    moveBackInternal(std::forward<T>(value)); // (1)    
    moveBackInternal(std::move(value));  // (2) 

} 

std::forward<T>(value) и std::move(value) являются идентичную в этом случае (это не имеет значения между (1) и (2) ... так что используйте (2)).

move - безусловный приведение к значению xvalue. Эта строка дает вам выражение типа T&&, это всегда значение rvalue.

forward - условный литье. Если T является ссылочным типом lvalue, он дает значение l. В противном случае (если это не ссылочный тип или ссылочный тип rvalue), он дает значение r. В нашем случае T не является ссылочным типом, поэтому мы получаем rvalue.

В любом случае, мы заканчиваем тем же пунктом - мы вызываем moveBackInternal с value литой как rvalue. Просто move() - это более простой способ добраться туда. forward<T>работает, но это не нужно.

+0

Его время от времени мне хотелось бы, чтобы я был в офисе с вами (или автором сообщения) и мог откровенно обсуждать с доской относительно лучшей техники. - Если я исхожу из предположения, что вся работа, выполняемая как 'std :: move', так и' std :: forward', - это время компиляции. Тогда решение (1) не было бы лучше, потому что это делает код похожим на 'emplace_back()'. Зачем мне нужны два разных метода, когда у меня может быть один метод, который работал во всех ситуациях? Меньше различий означает упрощение ведения кода? –

+0

@LokiAstari Похоже, в основном мнение основано. Я считаю более простым использовать 'move()', когда мы движемся безоговорочно. Код 'push_back()' только когда-либо перемещается, поэтому зачем использовать более сложный листинг? В конечном счете, я нахожу, что есть что-то принципиально ... с ... с пересылкой ссылок. Я не знаю, как это можно сделать лучше - и к лучшему или к худшему, это то, что мы получили. – Barry

+0

Спасибо за все входные данные. Честно говоря, я все еще пытаюсь сформировать свое мнение и просто пытаюсь сыграть здесь адвоката дьявола. :-) –