Ссылка Rvalue рассматривается как Lvalue?

Я отправил этот ответ: /questions/19037347/kak-mozhno-poluchit-ssyilku-na-rvalue/19037360#19037360 который содержит следующий код:

void foo(string&& bar){
    string* temp = &bar;

    cout << *temp << " @:" << temp << endl;
}

Является bar Rvalue или Lvalue?

Я спрашиваю, потому что я, очевидно, не могу взять адрес rvalue, но я могу взять адрес ссылки rvalue, как здесь.

Если вы можете выполнить какую-либо операцию со ссылкой на rvalue, которую вы можете выполнить со ссылкой на lvalue, то какой смысл различать эти два с помощью "&&" вместо просто "&"?

4 ответа

Решение

Является bar Rvalue или Lvalue?

Вопрос отвечает сам. Все, что имеет имя, является lvalue(1). Так bar это значение. Его тип является "rvalue ссылкой на string", но это lvalue этого типа.

Если вы хотите рассматривать это как значение, вам необходимо подать заявку std::move() к этому.


Если вы можете выполнить какую-либо операцию со ссылкой на rvalue, которую вы можете выполнить со ссылкой на lvalue, то какой смысл различать эти два с помощью "&&" вместо просто "&"?

Это зависит от вашего определения "выполнить операцию". Ссылка lvalue и (именованная) ссылка rvalue в значительной степени идентичны тому, как вы можете использовать их в выражениях, но они сильно различаются в том, что может с ними связываться. Lvalue может связываться со ссылками lvalue, rvalues ​​может связываться со ссылками rvalue (и все может связываться со ссылкой lvalue на const). То есть вы не можете привязать rvalue к ссылке lvalue или наоборот.

Давайте поговорим о параметре функции ссылочного типа rvalue (например, вашbar). Важным моментом не является то, чтоbarесть, но что вы знаете о ценности, к которой barотносится. поскольку bar является ссылкой на rvalue, вы наверняка знаете, что все, что с ней связано, было rvalue. Это означает, что оно обязательно будет уничтожено, когда закончится полное выражение, и вы можете смело обращаться с ним как со значением (путем кражи его ресурсов и т. Д.).

Если вы не тот, кто делает это напрямуюbar, но просто хочу пройтиbarу вас есть два варианта: либо вы закончили с barи затем вы должны сказать следующему, кто его получит, что он связан с rvalue - сделать std::move(bar), Или вам нужно сделать еще кое-что с barи поэтому вы не хотите, чтобы кто-то между ними крал у вас ресурсы, так что просто относитесь к нему как к значению bar,

Подводя итог:разница не в том, что вы можете сделать со ссылкой,когда она у вас есть.Разница в том, что можно привязать к ссылке.


(1) Хорошее практическое правило с небольшими исключениями: перечислители имеют имена, но являются значениями. Классы, пространства имен и шаблоны классов имеют имена, но не являются значениями.

Является ли бар значением или значением?

Это lvalue, как и любое выражение, которое называет переменную.

Если вы можете выполнить какую-либо операцию со ссылкой на rvalue, которую вы можете выполнить со ссылкой на lvalue, то какой смысл различать эти два с помощью "&&" вместо просто "&"?

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

std::string variable;
foo(variable);            // ERROR, can't pass an lvalue
foo(std::move(variable)); // OK, can explicitly move
foo("Hello");             // OK, can move from a temporary

Выражение bar это значение. Но это не "ссылка на строку". Выражение bar является ссылкой на lvalue. Вы можете проверить это, добавив следующую строку в foo():

cout << is_lvalue_reference<decltype((bar))>::value << endl; // prints "1" 

Но я согласен с остальным объяснением Angew.

Ссылка на rvalue, после того как она была привязана к rvalue, является ссылкой на lvalue. На самом деле это не только для параметров функции:

string&& a = "some string";
string&& b = a; // ERROR: it does not compile because a is not an rvalue

Если вы можете выполнить какую-либо операцию со ссылкой на rvalue, которую вы можете выполнить со ссылкой на lvalue, то какой смысл различать эти два с помощью "&&" вместо просто "&"?

Ссылка на rvalue позволяет нам выполнять некоторые "операции lvalue" до истечения срока действия rvalue.

Здесь в этом случае именованные ссылки rvalue являются lvalues, в то время как тип ввода const с именами ссылок rvalue, тогда это будет rvalue, вот простой пример:

#include <string>
#include <iostream>

void foo(const std::string&& bar) { 
    std::string* temp = &bar; // compile error, can't get address
    std::cout << *temp << " @:" << temp << std::endl;
}

int main()
{
    foo("test");
    return 0;
}

Надеюсь, это полезно.

Другие вопросы по тегам