[C++] 우측값(R-value)과 이동생성자

RisingJade의 개발기록·2022년 4월 12일
0

우측값


1. 개요

모든 C++ 식에는 형식이 있으며 값 범주에 속합니다. 값 범주는 식 평가 중에 임시 개체를 만들고, 복사하고, 이동할 때 컴파일러가 따라야 하는 규칙의 기초입니다.

C++17 표준은 다음과 같이 식 값 범주를 정의합니다.

  • lvalue에는 프로그램에서 액세스할 수 있는 주소가 있습니다. lvalue 식의 예로는 변수, 배열 요소, lvalue 참조, 비트 필드, 공용 구조체 및 클래스 멤버를 반환하는 함수 호출을 비롯한 const 변수 이름이 있습니다.

  • prvalue 식에는 프로그램에서 액세스할 수 있는 주소가 없습니다. prvalue 식의 예로는 리터럴, 참조가 아닌 형식을 반환하는 함수 호출 및 식 평가 중에 생성되지만 컴파일러에서만 액세스할 수 있는 임시 개체가 있습니다.

  • xvalue 식에는 프로그램에서 더 이상 액세스할 수 없지만 식에 대한 액세스를 제공하는 rvalue 참조를 초기화하는 데 사용할 수 있는 주소가 있습니다. 예를 들어 rvalue 참조를 반환하는 함수 호출과 배열 또는 개체가 rvalue 참조인 멤버 식에 대한 배열 아래 첨자, 멤버 및 포인터가 있습니다.

    출처: https://docs.microsoft.com/ko-kr/cpp/cpp/lvalues-and-rvalues-visual-cpp?view=msvc-170


2. 설명

보통 lvalue 위주로 코드를 짜고 대부분 lvalue에 값을 받아 사용해서 rvalue에 대해 제대로 생각해본적이 없다.
하지만 rvalue는 생각보다 여기저기에 들어가 있는 개념이며 위에 개요에서 말했듯 rvalue에 해당되는 것으로는 리터럴, 참조가 아닌 형식을 리턴하는 함수 호출, 식 평가 중에 생성되지만 컴파일러에서만 액세스할 수 있는 임시 개체가 있다.

ex)

int foo(){return 1;}
int a = foo() // 여기서 foo가 리턴하는 int형 값은 우측값
int b = 5 // 5또한 리터널이므로 당연히 우측값
  • 또한 rvalue를 참조하기 위해서 lvalue 참조 연산자인 &와 비슷한 모양의 &&를 쓴다.

3. 사용 사례

https://docs.microsoft.com/ko-kr/cpp/cpp/rvalue-reference-declarator-amp-amp?view=msvc-170 참고

4. 주의점


이동 생성자


1. 개요

복사 생성자처럼 굳이 새로운 메모리 공간을 할당하고 싶지 않을 때 주로 쓰인다. 또한 버려지는 rvalue을 다시 활용하려는 목적도 있다.

2. 설명

3. 사용 사례

보통 C++ 코드를 작성함에 있어 무심코 중복되고 복사되는 변수들이 많다. 예를 들어

class SampleString {
  char *content;  // 문자열 데이터를 가리키는 포인터
  int len;     // 문자열 길이

  int mem_capa;  // 현재 할당된 용량

 public:
  SampleString();

  // 복사 생성자
  SampleString(const SampleString &str);

  void reserve(int size);

  ~SampleString();
};

SampleString::SampleString(const SampleString &str) {
  std::cout << "복사 생성자call" << std::endl;
  len = str.len;
  mem_capa = str.len;
  content = new char[length];//새롭게 할당!

  for (int i = 0; i < len; ++i)
    content[i] = str.content[i];
}

위와 같이 복사 생성자로 복사를 하면 필연적으로 새로운 char[]을 할당해야한다. 그리고 만약 대입할 SampleString str을 나중에 안쓰고 잠깐 사용한 혹은 함수에서 리턴되는 값이였다면 str.content는 사라지는 것이 예정된 변수다.

  • 따라서! 우측값 참조 선언자인 &&를 이용해서 우측값을 받고 이동 생성자를 만들어 우측값을 받아서 해당 값의 변수를 그대로 갔다 쓰면 메모리를 새로 생성할 필요도 없고 str.content를 삭제할 이유도 없어진다!
  • 물론 str.content가 소멸할때 같이 소멸하지 않도록 이동생성자에서 std.content=null_ptr등으로 연결을 끊어주는 것을 잊지말자.

참고: https://modoocode.com/227

4. 주의점

profile
언제나 감사하며 살자!

0개의 댓글