Является ли возврат по ссылке rvalue более эффективным?


например:

Beta_ab&&
Beta::toAB() const {
    return move(Beta_ab(1, 1));
}
2 102

2 ответа:

Beta_ab&&
Beta::toAB() const {
    return move(Beta_ab(1, 1));
}

это возвращает висячую ссылку, как и в случае ссылки lvalue. После возврата функции временный объект будет уничтожен. Вы должны вернуться Beta_ab по значению, как показано ниже

Beta_ab
Beta::toAB() const {
    return Beta_ab(1, 1);
}

теперь он правильно перемещает временный Beta_ab объект в возвращаемое значение функции. Если компилятор может, он вообще избежит перемещения, используя RVO (оптимизация возвращаемого значения). Теперь вы можете сделать после

Beta_ab ab = others.toAB();

и он будет двигаться построить временный в ab, или сделать RVO, чтобы опустить выполнение перемещения или копирования в целом. Я рекомендую вам прочитать BoostCon09 Rvalue Ссылки 101 что объясняет этот вопрос, и как (N)RVO взаимодействует с этим.


ваш случай возврата ссылки rvalue был бы хорошей идеей в других случаях. Представьте, что у вас есть getAB() функция, которую вы часто вызываете на временной основе. Это не оптимально, чтобы он возвращал ссылку const lvalue для временных значений rvalue. Вы можете реализовать это так

struct Beta {
  Beta_ab ab;
  Beta_ab const& getAB() const& { return ab; }
  Beta_ab && getAB() && { return move(ab); }
};

отметим, что move в этом случае не является обязательным, так как ab не является ни локальным автоматическим, ни временным значением rvalue. Теперь ref-квалификатор&& говорит о том, что вторая функция вызывается на R-значения временных протезов, делая следующий шаг, вместо того, чтобы копировать

Beta_ab ab = Beta().getAB();

Это можете быть более эффективным, например, в несколько ином контексте:

template <typename T>
T&& min_(T&& a, T &&b) {
    return std::move(a < b? a: b);
}

int main() {
   const std::string s = min_(std::string("A"), std::string("B"));
   fprintf(stderr, "min: %s\n", s.c_str());
   return 0;
}

как интересное наблюдение, на моей машине clang++ -O3 генерирует 54 инструкции для кода выше против 62 инструкций для обычных std::min. Однако, с -O0 Он генерирует 518 инструкций для кода выше по сравнению с 481 для обычных std::min.