Возвращается с `std:: move` разумным в случае нескольких операторов возврата? - программирование

Возвращается с `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);

здесь, или я должен делать, а (ИМО уродливее, но спорно)

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

Ответ 1

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

§12.8 [class.copy] p32

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


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