значение для параметра std :: string - PullRequest
4 голосов
/ 10 апреля 2019

В чем разница между LVALUE и RVALUE в следующем коде, когда я передаю текст? Я имею в виду, в этом конкретном случае строки (где строка является строковым литералом), есть ли преимущество использования RVALUE (&&)?

void write_Lvalue(const std::string &text) {
    //...
}

void write_Rvalue(const std::string &&text) {
    //...
}

int main() {
    write_Lvalue("writing the Lvalue");
    write_Rvalue("writing the Rvalue");
}

Ответы [ 2 ]

4 голосов
/ 10 апреля 2019

Во-первых, постоянные ссылки на rvalue не очень полезны, так как вы не можете их перемещать. Движущееся значение требует изменяемых ссылок для работы.

Давайте возьмем ваш исправленный пример:

void write_lvalue(std::string const& text) {
    //...
}

void write_rvalue(std::string&& text) {
    //...
}

int main() {
    write_lvalue("writing the Lvalue");
    write_rvalue("writing the Rvalue");
}

В этом случае два полностью эквивалентны . В этих двух случаях компилятор должен создать строку и отправить ее по ссылке:

int main() {
    // equivalent, string created
    // and sent by reference (const& bind to temporaries)
    write_lvalue(std::string{"writing the Lvalue"}); 

    // equivalent, string created
    // and sent by reference (&& bind to temporaries)
    write_rvalue(std::string{"writing the Rvalue"});
}

Итак, почему есть функция, которая принимает rvalue ссылки?

Это зависит от того, что вы делаете со строкой. Изменяемая ссылка может быть перемещена из:

std::string global_string;

void write_lvalue(std::string const& text) {
    // copy, might cause allocation
    global_string = text;
}

void write_rvalue(std::string&& text) {
    // move, no allocation, yay!
    global_string = std::move(text);
}

Так зачем вообще использовать ссылку на rvalue? Почему бы не использовать изменяемую ссылку lvalue?

Это потому, что изменяемые ссылки lvalue не могут быть привязаны к временным файлам:

void write_lvalue_mut(std::string& text) {
    // move, no allocation... yay?
    global_string = std::move(text);
}

int main() {
    std::string s = /* ... */;
    write_lvalue_mut(std::move(s)); // fails
    write_lvalue_mut("some text"); // also fails
}

Но изменяемая ссылка на rvalue может быть связана с rvalue, как показано выше.

4 голосов
/ 10 апреля 2019

Там нет никакой пользы в этом случае. write_Rvalue будет принимать только значение. и write_Lvalue будет принимать только lvalue.

Когда вы передаете строковый литерал, из строкового литерала будет создан временный std::string. Вариант rvalue может уже связываться с этим, потому что вы уже передаете временный объект, а вариант lvalue может связываться с временным, потому что это const.

Это, например, не скомпилировать:

void write_Lvalue(const std::string &text) {
    //...
}

void write_Rvalue(const std::string &&text) {
    //...
}

int main() {
    std::string a = "hello";
    write_Rvalue(a);
}

потому что мы пытаемся передать lvalue a функции, принимающей только значение r.

Преимущество, которое можно получить с помощью типов значений, заключается в том, что их можно перемещать. Есть отличный пост о том, почему движение может быть быстрее здесь .

Создание вашего значения r const побеждает его назначение, хотя, как сказано в комментариях, потому что его нельзя больше перемещать.

...