l-value는 어떠한 메모리 위치를 가리키는데, & 연산자를 통해 그 위치를 참조할 수 있다.

r-value는 l-value가 아닌 값들, 대입 시 오른쪽에만 올 수 있는 value들이다. (임시 객체, 함수가 반환하는 객체, move()가 반환하는 값 등)

 

표현식 이후에 사라지면 r-value 사라지지 않으면 l-value

 

l-value reference 는 &하나로 정의

 

1. void foo(X&); 만 구현했을 경우

ㄴ foo는 좌측값만 인자로 받을 수 있다.

 

2. void foo(X const&);만 구현했을 경우

ㄴ foo는 좌측 값과 우측 값을 인자로 받을 수는 있지만 우측값일 때를 구별할 수가 없음

 

3.void foo(X &) or void foo(X const &); 와

   void foo(X &&); (우측 값만 받음) 모두 구현해야 구분할 수 있다.

 

우측값 참조라 선언되었더라도 이름이 있다면 좌측값 없다면 우측값이다.

예시 1.

void foo(X&& x) {
  X anotherX = x;  // x가 우측값 레퍼런스로 정의되었고 이름이 있기 때문에 좌측값이다. X(X const & rhs) 가 호출됨
}

 

예시 2.

X&& goo();
X x = goo();  // 이름이 없으므로 우측값. 즉 X(X&& rhs) 가 호출됨

 

std::move()

ㄴ 레퍼런스를 인자로 받고, 이것을 우측값 참조로 리턴하는 함수 (이름을 없애는 함수? 우측 값으로 바꿔주는 함수? 임시 객체를 리턴하는 함수?)

 

이동 생성자

MyString::MyString(MyString &&str) {
  std::cout << "이동 생성자 호출 !" << std::endl;
  string_length = str.string_length;
  string_content = str.string_content;
  memory_capacity = str.memory_capacity;

  // 임시 객체 소멸 시에 메모리를 해제하지
  // 못하게 한다.
  str.string_content = nullptr;
}


MyString::~MyString() {
  // 임시 객체의 string_content가 nullptr(0)이면 string_content를 해제하지 않는다.
  if (string_content) delete[] string_content; 
}

MyString str3 = str1 + str2; // operator+함수로 리턴된 임시 객체는 우측 값이다.

 

객체를 STL 컨테이너에 넣을 때, 이동 생성자 작성 시 주의할 점

STL 컨테이너들은 이동 생성자에서 예외가 발생했을 때 처리할 수 없기 때문에 이동 생성자를 noexcept로 명시하지 않으면 이동 생성자 대신 복사 생성자를 사용한다.

 

참조:

https://modoocode.com/227

+ Recent posts