수색…


가치 범주 의미

C ++의 표현식에는 해당 표현식의 결과에 따라 특정 값 카테고리가 지정됩니다. 표현식의 값 범주는 C ++ 함수 오버로드 해결에 영향을 줄 수 있습니다.

값 범주는 표현식에 대해 중요하지만 별도의 두 가지 속성을 결정합니다. 하나의 속성은 표현식에 ID가 있는지 여부입니다. 표현식은 변수 이름을 가진 객체를 참조하는 경우 ID를가집니다. 변수 이름은 표현식에 포함되지 않을 수도 있지만 객체는 여전히 표현식을 가질 수 있습니다.

다른 속성은 식의 값에서 암시 적으로 이동하는 것이 합법적인지 여부입니다. 또는 함수 매개 변수로 사용될 때 표현식이 r-value 매개 변수 유형에 바인딩되는지 여부를 결정합니다.

C ++은 lvalue (아이덴티티를 가진 표현식에서 이동 가능하지 않음), xvalue (아이덴티티가 이동식 인 표현식) 및 prvalue (이동성이없는 표현식)와 같은 3 가지 값 범주를 정의합니다. C ++에는 신원이없고 표현을 옮길 수없는 표현식이 없습니다.

C ++은 glvalue (식별이있는 표현식)와 rvalue (이동할 수있는 표현식)의 두 가지 값 범주를 정의합니다. 이들은 이전 범주의 유용한 그룹으로 작동합니다.

이 그래프는 그림으로 제공됩니다.

C ++ 언어의 가치 범주 그래프

예배당

prvalue (pure-rvalue) 표현식은 ID가없는 표현식으로, 일반적으로 평가는 객체를 초기화하는 데 사용되며 암시 적으로 이동할 수 있습니다. 여기에는 다음이 포함되지만 이에 국한되지는 않습니다 :

  • std::string("123") 과 같은 임시 객체를 나타내는 표현식입니다.
  • 참조를 반환하지 않는 함수 호출 식
  • 리터럴 (lvalues ​​인 문자열 리터럴 제외 )은 1 , true , 0.5f 또는 'a'
  • 람다 식

기본 제공 addressof 연산자 ( & )는이 표현식에 적용 할 수 없습니다.

x 값

xvalue (eXpiring 값) 표현식은 ID가 있고 암시 적으로 이동할 수있는 객체를 나타내는 표현식입니다. xvalue 표현식을 사용하는 일반적인 아이디어는 그들이 표현하는 객체가 곧 파괴 될 것이므로 (따라서 "eXpiring"부분), 따라서 암시 적으로 그들로부터 움직이는 것이 좋습니다.

주어진:

struct X { int n; };
extern X x;

4;                   // prvalue: does not have an identity
x;                   // lvalue
x.n;                 // lvalue
std::move(x);        // xvalue
std::forward<X&>(x); // lvalue
X{4};                // prvalue: does not have an identity
X{4}.n;              // xvalue: does have an identity and denotes resources
                     // that can be reused

좌변

lvalue 표현식은 ID가 있지만 암시 적으로 이동할 수없는 표현식입니다. 이 중 표현식은 변수 이름, 함수 이름, 내장 참조 연산자가 사용하는 표현식 및 왼쪽 값 참조를 참조하는 표현식으로 구성됩니다.

일반적인 lvalue는 단순한 이름이지만 lvalues는 다른 맛으로도 올 수 있습니다.

struct X { ... };

X x;         // x is an lvalue
X* px = &x;  // px is an lvalue
*px = X{};   // *px is also an lvalue, X{} is a prvalue

X* foo_ptr();  // foo_ptr() is a prvalue
X& foo_ref();  // foo_ref() is an lvalue

또한 대부분의 리터럴 (예 : 4 , 'x' 등)은 prvalues이지만 문자열 리터럴은 lvalues입니다.

glvalue

glvalue ( "일반화 된 lvalue") 표현식은 이동 여부에 관계없이 ID가있는 표현식입니다. 이 카테고리에는 lvalues ​​(식별이 있지만에서 이동할 수없는 표현식) 및 xvalues ​​(식별이 가능하고 이동할 수있는 표현식)가 포함되지만 prvalues ​​(식별이없는 표현식)는 제외됩니다.

표현식에 이름 이 있다면, 그것은 glvalue입니다 :

struct X { int n; };
X foo();

X x;
x; // has a name, so it's a glvalue
std::move(x); // has a name (we're moving from "x"), so it's a glvalue
              // can be moved from, so it's an xvalue not an lvalue

foo(); // has no name, so is a prvalue, not a glvalue
X{};   // temporary has no name, so is a prvalue, not a glvalue
X{}.n; // HAS a name, so is a glvalue. can be moved from, so it's an xvalue

가치

rvalue 표현식은 ID가 있는지 여부에 관계없이 내재적으로 이동할 수있는 모든 표현식입니다.

보다 정확하게, rvalue 표현식은 T && (여기서 Texpr 유형) 유형의 매개 변수를 취하는 함수의 인수로 사용될 수 있습니다. rvalue 표현식 이러한 함수 매개 변수에 대한 인수로 제공 될 수 있습니다. 비 rvalue 표현식이 사용되면, 과부하 해결은 rvalue 참조 매개 변수를 사용하지 않는 함수를 선택합니다. 그리고 존재하지 않으면 오류가 발생합니다.

rvalue 표현식의 범주에는 모든 xvalue 및 prvalue 표현식과 해당 표현식 만 포함됩니다.

표준 라이브러리 함수 std::move 는 비 rvalue 표현식을 rvalue로 명시 적으로 변환합니다. 더 구체적으로 표현식은 x 값으로 변환합니다. 이전에 신원이없는 prvalue 표현식 인 경우에도 std::move 의 매개 변수로 전달하여 신원 (함수의 매개 변수 이름)을 얻고 x 값이됩니다.

다음을 고려하세요:

std::string str("init");                       //1
std::string test1(str);                        //2
std::string test2(std::move(str));             //3

str = std::string("new value");                //4 
std::string &&str_ref = std::move(str);        //5
std::string test3(str_ref);                    //6

std::string 에는 std::string&& 유형의 단일 매개 변수를 취하는 생성자가 있으며 일반적으로 "이동 생성자"라고합니다. 그러나 표현식 str 의 값 범주는 rvalue가 아니며 (특히 lvalue 임) 해당 생성자 오버로드를 호출 할 수 없습니다. 대신 const std::string& overload라는 복사본 생성자를 호출합니다.

3 호선이 사물을 바꿉니다. std::move 의 반환 값은 T&& . 여기서 T 는 전달 된 매개 변수의 기본 유형이므로 std::move(str)std::string&& 반환합니다. 리턴 값이 rvalue reference 인 함수 호출은 rvalue 표현식 (특히 xvalue)이므로 std::string 의 이동 생성자를 호출 할 수 있습니다. 3 행 다음에 str 이 이동되었습니다 (누가 컨텐츠가 정의되지 않았습니까).

4 행은 임시 연산자를 std::string 의 대입 연산자로 전달 std::string . 이 std::string&& 걸리는 오버로드가 있습니다. std::string("new value") 표현식은 rvalue 표현식 (특히 prvalue)이므로 해당 오버로드를 호출 할 수 있습니다. 따라서, 임시는 str 으로 이동되어, 정의되지 않은 내용을 특정 내용으로 대체합니다.

5 행은 str_ref 라는 str 을 참조하는 명명 된 rvalue 참조를 만듭니다. 이것은 가치 범주가 혼란스러워하는 곳입니다.

반면, 참조 str_ref 를 rvalue의 수 기준입니다 std::string , 식의 값 범주 str_ref 를 rvalue 없습니다. 그것은 lvalue 표현입니다. 네 진짜로 요. 이 때문에 std::string 의 이동 생성자를 str_ref 표현식으로 호출 할 수 없습니다. 따라서 라인 6은 str 의 값을 test3 복사 합니다.

그것을 옮기기 위해서, 우리는 다시 std::move 를 사용해야 할 것입니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow