Введение
ISOC ++ 11 (официально ISO / IEC 14882: 2011) является самой последней версией стандарта языка программирования C ++. Он содержит некоторые новые функции и концепции, например:
- rvalue ссылки
- категории значений выражений xvalue, glvalue, prvalue
- семантика перемещения
Если мы хотим понять концепции новых категорий значений выражений, мы должны знать, что существуют ссылки на rvalue и lvalue.
Лучше знать, что значения могут быть переданы неконстантным ссылкам значения.
int& r_i=7; // compile error
int&& rr_i=7; // OK
Мы можем получить некоторое представление о понятиях категорий значений, если процитируем подраздел «Значения и значения» из рабочего проекта N3337 (наиболее похожего на опубликованный стандарт ISOC ++ 11).
3.10 Lvalues и rvalues [basic.lval]
1 Выражения классифицированы в соответствии с таксономией на рисунке 1.
- lvalue (так называемое исторически, потому что lvalue может появляться в левой части выражения присваивания) обозначает функцию
или объект. [Пример: если E является выражением типа указателя, то
* E является выражением lvalue, относящимся к объекту или функции, на которую указывает E. В качестве другого примера, результат вызова функции
тип возвращаемого значения - ссылка lvalue - lvalue. - конец примера]
- Значение xvalue (значение «eXpiring») также относится к объекту, обычно ближе к концу его времени жизни (так что его ресурсы могут быть перемещены, для
пример). Xvalue является результатом некоторых видов выражений
включая ссылки на значения (8.3.2). [Пример: результат вызова
функция, тип возвращаемой которой является ссылкой на rvalue, является xvalue. -конец
пример]
- glvalue («обобщенное» lvalue) - это lvalue или xvalue.
- rvalue (так называемое исторически, потому что rvalue может появиться в правой части выражения присваивания) - это xvalue, a
временный объект (12.2) или его подобъект, или значение, которое не является
связанный с объектом.
- prvalue («чистое» rvalue) - это rvalue, которое не является xvalue. [Пример: результат вызова функции, тип возврата которой не является
ссылка является prvalue. Значение литерала, такого как 12, 7.3e5 или
истина также prvalue. - конец примера]
Каждое выражение принадлежит ровно одному из фундаментальных
классификации в этой таксономии: lvalue, xvalue или prvalue. это
Свойство выражения называется его категорией значения.
Но я не совсем уверен в том, что этого подраздела достаточно для четкого понимания концепций, потому что "обычно" не является действительно общим, "ближе к концу его срока службы" не совсем конкретно, "использование ссылок на rvalue" не является действительно ясно, и «Пример: результатом вызова функции, тип возвращаемой которой является ссылкой на rvalue, является значение xvalue». Похоже, змея кусает свой хвост.
КАТЕГОРИИ ПЕРВИЧНОЙ ЦЕННОСТИ
Каждое выражение принадлежит ровно одной категории первичных значений. Этими категориями значений являются категории lvalue, xvalue и prvalue.
lvalues
Выражение E относится к категории lvalue тогда и только тогда, когда E относится к объекту, у которого УЖЕ есть идентификатор (адрес, имя или псевдоним), который делает его доступным вне E.
#include <iostream>
int i=7;
const int& f(){
return i;
}
int main()
{
std::cout<<&"www"<<std::endl; // The expression "www" in this row is an lvalue expression, because string literals are arrays and every array has an address.
i; // The expression i in this row is an lvalue expression, because it refers to the same entity ...
i; // ... as the entity the expression i in this row refers to.
int* p_i=new int(7);
*p_i; // The expression *p_i in this row is an lvalue expression, because it refers to the same entity ...
*p_i; // ... as the entity the expression *p_i in this row refers to.
const int& r_I=7;
r_I; // The expression r_I in this row is an lvalue expression, because it refers to the same entity ...
r_I; // ... as the entity the expression r_I in this row refers to.
f(); // The expression f() in this row is an lvalue expression, because it refers to the same entity ...
i; // ... as the entity the expression f() in this row refers to.
return 0;
}
xvalues
Выражение E относится к категории xvalue тогда и только тогда, когда оно равно
- результат вызова функции, явной или неявной, тип возвращаемого значения которой является rvalue ссылкой на тип возвращаемого объекта, или
int&& f(){
return 3;
}
int main()
{
f(); // The expression f() belongs to the xvalue category, because f() return type is an rvalue reference to object type.
return 0;
}
- приведение к rvalue-ссылке на тип объекта или
int main()
{
static_cast<int&&>(7); // The expression static_cast<int&&>(7) belongs to the xvalue category, because it is a cast to an rvalue reference to object type.
std::move(7); // std::move(7) is equivalent to static_cast<int&&>(7).
return 0;
}
- классвыражение доступа к элементу, обозначающее нестатический член данных не ссылочного типа, в котором выражение объекта является значением xvalue, или
struct As
{
int i;
};
As&& f(){
return As();
}
int main()
{
f().i; // The expression f().i belongs to the xvalue category, because As::i is a non-static data member of non-reference type, and the subexpression f() belongs to the xvlaue category.
return 0;
}
- выражение указателя на член, в которомпервый операнд - это значение xvalue, а второй операнд - указатель на элемент данных.
Обратите внимание, что эффект приведенных выше правил заключается в том, что именованные ссылки на значения rvalue обрабатываются как lvalues, а безымянные ссылки на rvalueобъекты рассматриваются как значения x;rvalue ссылки на функции обрабатываются как lvalues независимо от того, названы они или нет.
#include <functional>
struct As
{
int i;
};
As&& f(){
return As();
}
int main()
{
f(); // The expression f() belongs to the xvalue category, because it refers to an unnamed rvalue reference to object.
As&& rr_a=As();
rr_a; // The expression rr_a belongs to the lvalue category, because it refers to a named rvalue reference to object.
std::ref(f); // The expression std::ref(f) belongs to the lvalue category, because it refers to an rvalue reference to function.
return 0;
}
prvalues
Выражение E относится к категории prvalue тогда и только тогда, когдаE не относится ни к lvalue, ни к категории xvalue.
struct As
{
void f(){
this; // The expression this is a prvalue expression. Note, that the expression this is not a variable.
}
};
As f(){
return As();
}
int main()
{
f(); // The expression f() belongs to the prvalue category, because it belongs neither to the lvalue nor to the xvalue category.
return 0;
}
КАТЕГОРИИ СМЕШАННЫХ ЗНАЧЕНИЙ
Есть еще две важные категории смешанных значений.Этими категориями значений являются категории rvalue и glvalue.
rvalues
Выражение E принадлежит категории rvalue тогда и только тогда, когда E принадлежит категории xvalue,или к категории prvalue.
Обратите внимание, что это определение означает, что выражение E относится к категории rvalue, если и только если E относится к объекту, который не имеет какой-либо идентичности, которая делает его доступным за пределамиE YET.
glvalues
Выражение E относится к категории glvalue тогда и только тогда, когда E принадлежит категории lvalue или категории xvalue.
ПРАКТИЧЕСКОЕ ПРАВИЛО
Скотт Мейер опубликовал 1131 * очень полезное эмпирическое правило, позволяющее отличить значения от l-значений.
- Если вы можете взять адрес выражения, выражение будет lvalue.
- Если тип выражения является ссылкой lvalue (например, T & или const T & и т. Д.), это выражение является лзначение.
- В противном случае выражение является значением r.Концептуально (и обычно также фактически) значения соответствуют временным объектам, таким как возвращаемые из функций или созданные неявными преобразованиями типов.Большинство литеральных значений (например, 10 и 5.3) также являются rvalues.