소개
ISOC ++ 11 (공식적으로 ISO / IEC 14882 : 2011)은 C ++ 프로그래밍 언어 표준의 최신 버전입니다. 여기에는 몇 가지 새로운 기능과 개념이 포함되어 있습니다.
- rvalue 참조
- xvalue, glvalue, prvalue 표현식 값 범주
- 의미론 이동
새로운 표현식 값 범주의 개념을 이해하려면 rvalue 및 lvalue 참조가 있음을 알고 있어야합니다. rvalue가 상수가 아닌 rvalue 참조로 전달 될 수 있다는 것을 아는 것이 좋습니다.
int& r_i=7; // compile error
int&& rr_i=7; // OK
작업 초안 N3337 (게시 된 ISOC ++ 11 표준과 가장 유사한 초안)에서 Lvalues 및 rvalues라는 하위 섹션을 인용하면 가치 범주 개념에 대한 직관을 얻을 수 있습니다.
3.10 L 값과 r 값 [basic.lval]
1 표현은 그림 1의 분류법에 따라 분류됩니다.
- lvalue (역사적으로 lvalue는 대입 표현식의 왼쪽에 나타날 수 있기 때문에 소위)는 함수 또는 객체를 지정합니다. [예 : E가 포인터 유형의 표현식 인 경우 * E는 E가 가리키는 오브젝트 또는 함수를 참조하는 lvalue 표현식입니다. 다른 예로, 리턴 유형이 lvalue 참조 인 함수를 호출 한 결과는 lvalue입니다. — 끝 예제]
- xvalue ( "eXpiring"값)는 일반적으로 수명이 거의 다 된 객체 (예 : 리소스가 이동 될 수 있음)를 나타냅니다. xvalue는 rvalue 참조 (8.3.2)와 관련된 특정 종류의 표현식의 결과입니다. [예 : 반환 유형이 rvalue 참조 인 함수를 호출 한 결과는 xvalue입니다. — 끝 예제]
- glvalue ( "일반화"lvalue)는 lvalue 또는 xvalue입니다.
- rvalue (역사적으로 rvalue가 대입 표현식의 오른쪽에 나타날 수 있기 때문에 소위)는 xvalue,
임시 객체 (12.2) 또는 그 하위 객체 또는 객체
와 관련 되지 않은 값입니다 .
- prvalue ( "순수"rvalue)는 xvalue가 아닌 rvalue입니다. [예 : 반환 유형이
참조가 아닌 함수를 호출 한 결과 는 prvalue입니다. 12, 7.3e5 또는
true 와 같은 리터럴 값 도 prvalue입니다. — 끝 예제]
모든 표현은이 분류 체계의 기본 분류 중 하나 인 lvalue, xvalue 또는 prvalue에 속합니다. 식의이 속성을 값 범주라고합니다.
그러나 나는 "보통"이 실제로 일반적이지 않고 "평생의 끝이 가까움"이 실제로 구체적이지 않기 때문에이 하위 섹션이 개념을 명확하게 이해하기에 충분하다는 것을 확신하지 못한다. "예 : 반환 유형이 rvalue 참조 인 함수를 호출 한 결과는 xvalue입니다." 뱀이 꼬리를 물고있는 것처럼 들린다.
기본 가치 카테고리
모든 표현식은 정확히 하나의 기본 값 범주에 속합니다. 이러한 가치 범주는 lvalue, xvalue 및 prvalue 범주입니다.
l 값
E가 ALREADY에 E 외부에서 액세스 할 수있는 ID (주소, 이름 또는 별명)가있는 엔티티를 참조하는 경우에만 표현식 E가 lvalue 카테고리에 속합니다.
#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;
}
x 값
식 E는 xvalue 범주 인 경우에만 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 참조가 lvalue로 취급되고 객체에 대한 명명되지 않은 rvalue 참조는 xvalue로 취급된다는 점에 유의하십시오. 함수에 대한 rvalue 참조는 명명 여부에 관계없이 lvalue로 처리됩니다.
#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;
}
전치
E가 lvalue 또는 xvalue 범주에 속하지 않는 경우에만 표현식 E는 prvalue 범주에 속합니다.
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가 xvalue 범주 또는 prvalue 범주에 속하는 경우에만 표현식 E가 rvalue 범주에 속합니다.
이 정의는 E가 E YET 외부에서 액세스 할 수 있도록하는 ID가없는 엔티티를 참조하는 경우에만 표현식 E가 rvalue 범주에 속함을 의미합니다.
glvalues
E가 lvalue 범주 또는 xvalue 범주에 속하는 경우에만 표현식 E는 glvalue 범주에 속합니다.
실제 규칙
Scott Meyer는 rvalue와 lvalue를 구별하기 위해 매우 유용한 경험 법칙을 발표 했습니다.
- 식의 주소를 사용할 수 있으면 식은 lvalue입니다.
- 표현식의 유형이 lvalue 참조 (예 : T & 또는 const T & 등) 인 경우 해당 표현식은 lvalue입니다.
- 그렇지 않으면 표현식은 rvalue입니다. 개념적으로 (그리고 실제로도) rvalue는 함수에서 반환되거나 암시 적 형식 변환을 통해 생성 된 것과 같은 임시 개체에 해당합니다. 대부분의 리터럴 값 (예 : 10 및 5.3)도 rvalue입니다.