씹어먹는 C++
13장 우측값과 이동 연산 630p-648p
컴파일러 자체에서 복사를 생략해 버리는 작업
필요에 따라 굳이 임시 객체를 한 번 만들고, 이를 복사 생성할 필요 없음
(함수의 인자가 아닌) 함수 내부에서 생성된 객체를 그대로 리턴할 때, 복사 생략 수행
string_content = nullptr;
좌측값 (lvalue)
좌측값은 어떠한 표현식의 왼쪽 오른쪽 모두 가능
메모리 상에서 존재하는 변수
우측값(rvalue)
표현식을 연산 시에만 잠깐 존재할 뿐 연산 후 사라지는 값
실체가 없는 값
우측값은 항상 오른쪽
example code
int a; // a 는 좌측값
int& l_a = a; // l_a 는 좌측값 레퍼런스
int& r_b = 3; // 3 은 우측값. 따라서 오류
’좌측값’ 에만 레퍼런스를 가질수 있음
& 하나를 이용해서 정의하는 레퍼런스
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값 리턴시 리턴 값은 실체가 없음
& 를 두 개 사용해서 정의
우측값만 특이적으로 받기 위해 사용
레퍼런스를 갖는 해당 임시 객체가 소멸되지 안도록 한다.
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이 아닌 이상 이동 생성자를 사용하지 않음