Ссылка 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;
}
Надеюсь, это полезно.