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

Ответы:

247
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 References 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 && говорит, что вторая функция вызывается во временных файлах rvalue, делая следующий ход вместо копирования

Beta_ab ab = Beta().getAB();
Йоханнес Шауб - litb
источник
51
Я всегда предполагал, что проблема с висячими ссылками исчезает автоматически, когда возвращаемым типом была ссылка на r-значение. Рад, что я исправил это, прежде чем он меня укусил. Отстойное уничтожение стека ошибок.
deft_code
31
:) На самом деле ссылки rvalue - это "просто ссылки", как и ссылки lvalue. они ничего не копируют и не хранят.
Йоханнес Шауб - лит
9
что делает квалификатор const & для функции-члена больше, чем простая константа?
Галинетт
4
+ 1-е изд, но неработающая ссылка: BoostCon09 Rvalue Ссылки 101
Siu Ching Pong -Asuka Kenji-
3
@galinette Это ссылочные квалификаторы .
Малькольм
2

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

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.

wonder.mice
источник
Меня смущает твой ответ. Пробовал похожую (возможно) версию, но не получилось: ideone.com/4GyUbZ Не могли бы вы объяснить, почему?
Deqing
Вы использовали ссылку на временный объект for(:)и интегрировали освобожденный объект. Исправление: ideone.com/tQVOal
wonder.mice
4
не правда ли, это неправильный ответ для параметра шаблона T, T && не является ссылкой на значение r, а скорее универсальной ссылкой, и в этом случае мы всегда должны вызывать std :: forward <T>, а не std :: move! Не говоря уже о том, что этот ответ прямо противоречит приведенному выше ответу, получившему наибольшее количество голосов.
xdavidliu 03
@xdavidliu, этот ответ - надуманный пример того, как возврат по rvalue может быть более эффективным. std::move()используется просто как явное приведение, чтобы более четко проиллюстрировать суть. Это не тот код, который вы бы скопировали и вставили в свой проект. Это не противоречит ответу, получившему наибольшее количество голосов, потому что внутри функции создается временный объект. Здесь возвращаемый объект является одним из аргументов (временные объекты уничтожаются на последнем этапе оценки полного выражения, которое (лексически) содержит точку, в которой они были созданы).
wonder.mice
2
@ wonder.mice, тогда замените T на std :: string; здесь вообще нет необходимости использовать шаблоны, а использование T && в качестве ссылки на r-значение - просто ужасный стиль, который излишне сбивает с толку людей, плохо знакомых с шаблонами и r-значениями.
xdavidliu