Rvalue & Lvalue

SOEUN CHOI·2022년 6월 15일
0

C++_study

목록 보기
10/15

씹어먹는 C++

13장 우측값과 이동 연산 630p-648p


복사 생략(Copy Elision)

컴파일러 자체에서 복사를 생략해 버리는 작업
필요에 따라 굳이 임시 객체를 한 번 만들고, 이를 복사 생성할 필요 없음
(함수의 인자가 아닌) 함수 내부에서 생성된 객체를 그대로 리턴할 때, 복사 생략 수행

  • nullptr
    기존의 NULL 대체
    포인터 주소값 0 정확히 명시
    string_content = nullptr;
  • 만약 복사 생략 수행하지 않을시
    쓸데 없는 복사를 두 번 하는데 상당한 자원이 소모
    어차피 똑같이 복사해서 생성할 것이면, 이미 생성된 (str1 + str2) 가 리턴한 객체를 str3으로 사용가능

    해당 문제를 해결하려면
    str3 생성 시에 임시로 생성된 객체의 string_content 가리키는 문자열의 주소값을 str3 의 string_content
    문자열 사라짐 방지를 위해 nullptr로 사용

좌측값 (lvalue) 와 우측값 (rvalue)

  • 좌측값 (lvalue)
    좌측값은 어떠한 표현식의 왼쪽 오른쪽 모두 가능
    메모리 상에서 존재하는 변수

  • 우측값(rvalue)
    표현식을 연산 시에만 잠깐 존재할 뿐 연산 후 사라지는 값
    실체가 없는 값
    우측값은 항상 오른쪽

example code

int a; // a 는 좌측값
int& l_a = a; // l_a 는 좌측값 레퍼런스
int& r_b = 3; // 3 은 우측값. 따라서 오류

좌측값 레퍼런스 (lvalue reference)

’좌측값’ 에만 레퍼런스를 가질수 있음
& 하나를 이용해서 정의하는 레퍼런스

int& func1(int& a) { return a; }
int func2(int b) { return b; }
int main() {
  int a = 3;
  func1(a) = 4;
  std::cout << &func1(a) << std::endl;

  int b = 2;
  a = func2(b); // 가능
  func2(b) = 5; // 오류 1
  std::cout << &func2(b) << std::endl; // 오류 
}

위 예시 처럼
래퍼런스 리턴시 리턴값의 주소값을 가져오는 것 가능
lvalue로 사용 가능
하지만
일반 int값 리턴시 리턴 값은 실체가 없음

  • const 레퍼런스
    예외적 타입에 한해서 우측값도 래퍼런스로 받기 가능
    임시로 존재하는 객체의 값을 참조만 가능 변경 불가능 하기 때문

우측값 레퍼런스

& 를 두 개 사용해서 정의
우측값만 특이적으로 받기 위해 사용
레퍼런스를 갖는 해당 임시 객체가 소멸되지 안도록 한다.

example code

int a;
int& l_a = a;
int& ll_a = 3; // 불가능
int&& r_b = 3;
int&& rr_b = a; // 불가능

이동 생성자

우측값 래퍼런스를 사용한 이동 생성자

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타입의 우측값 인자 받음.
기존의 복사 생성자의 경우 문자열 전체를 새로 복사,
이동 생성자의 경우 단순히 주소값 하나만 복사.

주소값을 복사하므로
임시 객체가 소멸 시 delete 안 되도록 해야함
즉, 소멸자 또한 nullptr이 아닐 때만 delete

  • vector 복사 생성자 이용시
    복사 생성 과정에서 예외 발생시 새로 할당한 메모리 소멸 후 예외처리

  • 하지만 vector 이동 생성자 이용시
    이동 생성의 경우 기존 메모리를 원소에 이동시켰으므로 기존에 메모리에 남은 원소들이 없음
    즉, 섯불리 해제 불가능
    vector는 noexcept이 아닌 이상 이동 생성자를 사용하지 않음

profile
soeun choi

0개의 댓글