R-значение в C++0x
Значения ИМХО являются большим улучшением в C++, но в начале они кажутся довольно запутанными. Пожалуйста, посмотрите на код ниже:
#include <string>
std::string && foo (void)
{
std::string message ("Hello!");
return std::move (message);
}
void bar (const std::string &message2)
{
if (message2 == "Bye Bye!")
return;
}
int main ()
{
bar (foo ());
}
Ссылка message2
последний владелец оригинала message
объект, возвращенный foo()
, право?
2 ответа
Нет, это не правильно. Вы попали в обычную ловушку, которую делаете один, когда обнаружили ссылку на значение, как и Мотти в принятом ответе! (И я тоже сделал эту ошибку, в моем предыдущем тесте с rref)
Если вы не хотите стрелять себе в ногу при работе с rref, усвойте это:
В большинстве случаев функция, возвращающая ссылку на rvalue, так же глупа, как и функция, возвращающая нормальную ссылку.
Потому что rvalue ссылки... ссылки! Так что если вы вернете ссылку - значение или нет - на message
вы возвращаете ссылку на объект, который был только что уничтожен, потому что он вышел из области видимости, поэтому вы возвращаете висячую ссылку. Это ошибка.
Кроме того, не пишите return std::move(message)
потому что компилятор уже знает, что message
является временным значением (r-значением), поэтому нет необходимости изменять его с помощью std::move. И на самом деле, написание return std::move(something)
может предотвратить оптимизацию (по крайней мере на MSVC10, кажется, отключить RVO).
Итак, правильный и самый эффективный способ это:
#include <string>
std::string foo (void)
{
std::string message ("Hello!");
return message;
}
void bar (const std::string& message2)
{
if (message2 == "Bye Bye!")
return;
}
int main ()
{
bar (foo());
}
Старый добрый C++03:)
Потому что NRVO начинает действовать, и нет ни копии, ни движения, только одна конструкция.
Изменить: Возврат ссылки R-значение не то, что вы хотите сделать. Этот ответ был первоначально написан, когда я все еще начинал понимать ссылки R-значения в C++11s.
Ты прав, message2
будет построен с использованием конструктора перемещения, так что он может уничтожить память, выделенную message
в foo
однако это может не произойти, если используется оптимизация небольшой строки, тогда конструктор перемещения для короткой строки не будет более эффективным, чем конструктор копирования.
Еще одна вещь, которую стоит отметить, это то, что вам не нужно явно использовать std::move
при возврате значения возвращаемые значения известны как ссылки на r-значения.