Имеет ли смысл возвращение с помощью `std::move` в случае множественных операторов возврата?

Я знаю, что обычно возвращаться с std::moveт.е.

bigObject foo() { bigObject result; /*...*/ return std::move(result); }

вместо просто

bigObject foo() { bigObject result; /*...*/ return result; }

потому что это мешает оптимизации возвращаемого значения. Но что в случае функции с несколькими различными возвратами, особенно что-то вроде

class bar {
  bigObject fixed_ret;
  bool use_fixed_ret;
  void prepare_object(bigObject&);
 public:
  bigObject foo() {
    if(use_fixed_ret)
      return fixed_ret;
     else{
      bigObject result;
      prepare_object(result);
      return result;
    }
  }
};

Я думаю, что нормальная оптимизация возвращаемого значения невозможна в такой функции, поэтому было бы неплохо добавить

      return std::move(result);

здесь, или я должен делать, а (IMO уродливее, но это спорный вопрос)

  bigObject foo() {
    bigObject result;
    if(use_fixed_ret)
      result = fixed_ret;
     else{
      prepare_object(result);
    }
    return result;
  }

1 ответ

Решение

Для локальных переменных нет необходимости std::move их в return утверждение большую часть времени, поскольку язык фактически требует, чтобы это происходило автоматически:

§12.8 [class.copy] p32

Когда критерии для исключения операции копирования выполнены или будут выполнены, за исключением того факта, что исходный объект является параметром функции, а копируемый объект обозначен lvalue, разрешением перегрузки для выбора конструктора для копирования является сначала выполняется, как если бы объект был обозначен как rvalue. Если не удается разрешить перегрузку или если тип первого параметра выбранного конструктора не является rvalue-ссылкой на тип объекта (возможно, cv-квалифицированный), разрешение перегрузки выполняется снова, рассматривая объект как lvalue. [ Примечание: это двухэтапное разрешение перегрузки должно выполняться независимо от того, будет ли выполнено копирование. Он определяет конструктор, который будет вызван, если elision не выполняется, и выбранный конструктор должен быть доступен, даже если вызов исключен. —Конечная записка ]


† Исключение копирования очень ограничено в том месте, где оно может быть применено (§12.8/31). Одним из таких ограничений является то, что тип исходного объекта должен быть таким же, как и у cv-неквалифицированного возвращаемого типа функции при работе с оператором return. Это также не применимо для подобъектов локальных переменных, которые собираются выйти из области видимости.

Другие вопросы по тегам