C++ 아이콘 제작자: Darius Dan - Flaticon
C++의 모든 식은 타입과 값 카테고리를 가진다. 아래를 기준을 하여 5개가 있다.
• 정체를 알 수 있는가?
정체를 알 수 있다는 말은 해당 식이 어떤 다른 식과 같은 것인지 아닌지 를 구분할 수 있다는 말
일반적인 변수라면 주소값을 취해서 구분할 수 있겠고 함수의 경우라면 그냥 이름만 확인해보면 됨
• 이동 시킬 수 있는가?
해당 식을 다른 곳으로 안전하게 이동할 수 있는지?
즉 해당 식을 받는 이동 생성자, 이동 대입 연산자 등을 사용할 수 있어야만 한다.
이동 가능(rvalue) | 이동 불가능 | |
---|---|---|
정체를 알 수 있다(glvalue) | xvalue | lvalue |
정체를 알 수 없다 | prvalue | 쓸모 없음 |
(pure rvalue) 순수 우측값
(eXpiring value) 소멸하는 값
(generalized lvalue) 일반화된 좌측값
int* pi = &i 에서는 pi는 lvalue로 i의 주소를 가지지만 다른 곳에서 rvalue로 값을 가져올 수 있다.
여기서 i의 정체를 알 수 있나??
i의 주소값을 알 수 있으니 알 수 있다.
==> 주소값 연산자(&) 를 통해 해당 식의 주소값을 알아 낼 수 있다.
이동이 가능한가?
아니다int&& x = i;
는 컴파일 안된다
- 변수, 어떤 타입의 데이터 멤버 (예컨대 std::endl, std::cin) 등등
- 좌측값 레퍼런스를 리턴하는 함수의 호출식. std::cout << 1 이나 ++it 같은 것들
- a = b, a += b, a *= b 같이 복합 대입 연산자 식들
- ++a, --a 같은 전위 증감 연산자 식들
- a.m, p->m 과 같이 멤버를 참조할 때. 이 때 m 은 enum 값이거나 static 이 아닌 멤버 함수인 경우 제외.
- a[n] 과 같은 배열 참조 식들
- 문자열 리터럴 "hi"
class A { int f(); // static 이 아닌 멤버 함수 static int g(); // static 인 멤버 함수 } A a; a.g; // lvalue a.f; // prvalue
void f(int&& a) {
a; // <-- ?
}
- a 는 우측값 레퍼런스기는 하지만 함수 내부의 식 a 의 경우는 lvalue 이다.
왜냐면 주소값을 구할 수 있기 때문이다.- 식 a 의 타입 은 우측값 레퍼런스가 맞지만 식 a 의 값 카테고리 는 lvalue가 된다.
int f() { return 10; }
f();
f()는 주소값을 가져올 수 없다 하지만 우측값 레퍼런스에 넣을 수 있다. ==> prvalue
- 문자열 리터럴을 제외 한 모든 리터럴들. 42, true, nullptr 같은 애들
- 레퍼런스가 아닌 것을 리턴하는 함수의 호출식. 예를 들어서 str.substr(1, 2), str1+ str2
- 후위 증감 연산자 식. a++, a--
- 산술 연산자, 논리 연산자 식들. a + b, a && b, a < b 같은 것들을 말합니다.
==> 물론 이들은 연산자 오버로딩 된 경우들 말고 디폴트로 제공되는 것들을 말한다.- 주소값 연산자 식 &a
- a.m, p->m 과 같이 멤버를 참조할 때. 이 때 m 은 enum 값이거나 static 이 아닌 멤버 함수여야함.
- this
- enum 값
- 람다식 { return 0;}; 과 등등 ...
prvalue 들은 식의 좌측에 올 수 없다, 항상 우측에 와야함
상수 좌측값 레퍼런스와 우측값 레퍼런스를 초기화하는데 사용 가능.const int& r = 42; int&& rr = 42;
우측값 레퍼런스를 리턴하는 함수의 호출식이 있다.
대표적으로 std::move(x)가 있다
개인 공부 기록용 블로그입니다.
틀린 부분 있으다면 지적해주시면 감사하겠습니다!!