C++11에서 가장 핵심적인 변화.

 

lvalue : 단일식을 넘어서 계속 지속되는 개체

rvalue : lvalue가 아닌 나머지. (임시 값, 열거형, 람다, i++ 등)

 

void TestKnight_Copy(Knight knight) {} // 값 복사
void TestKnight_LValueRef(Knight& knight) {} // 참조
void TestKnight_ConstLValueRef(const Knight& knight) {} // 임시 객체도 넘겨줄 수 있음

TestKnight_ConstLValueRef(Knight()); // 임시 객체도 넘겨줄 수 있음

기존의 문법들

 

void TestKnight_RValueRef(Knight&& knight) {}

Knight k1;
TestKnight_RValueRef(k1) // 오류!

오른값 참조를 받을때는 인자로 && 를 받으면 되는데 왼값은 인자로 받을 수 없다.

static_cast<Knight&&>를 하면 쓸수 있기는 하다.

 

그럼 오른값 참조를 하는 이유는?

원본을 더 이상 사용하지 않을 것이라는 힌트를 제공해준다.

기존의 복사 생성자는 얕은 복사를 우려해서 깊은 복사를 구현했는데, 복사 대상의 객체 크기가 클수록 복사 비용이 커지는 문제가 있다.

하지만 오른값 참조로 받은 값은 인자로 넘겨준 시점에서 더이상 쓰지 않겠다고 알려준거나 다름없기 때문에 값을 마음대로 수정해도 상관이 없으므로 얕은 복사로 데이터를 모두 이동시켜도 무방하다. (이동의 개념)

class Knight
{
public:
	// 이동 생성자
    Knight(Knight&& knight)
    {
        // do something
    }

	// 이동 대입 연산자
    void operator=(Knight&& knight)
    {
        _hp = knight._hp;
        _pet = knight._pet;
        knight._pet = nullptr;
    }
}

 

 

std::move

오른값 참조로 캐스팅을 한 것과 같다.

이름이 move라서 무언가 옮겨줄 것 같지만 lvalue를 rvalue로 캐스팅 해주는 것에 불과하다.

Knight k1;
Knight k2;

k1 = static_cast<Knight&&>(k2);
k1 = std::move(k2); // 위와 동일
// 여담으로 move의 이름 후보 중 하나가 rvalue_cast 였다고 함

 

차후 다룰 unique_ptr에서 활용할 때가 있다.

'C++ > Rookiss C++' 카테고리의 다른 글

[Modern C++] 람다 (lambda)  (0) 2022.08.31
[Modern C++] 전달 참조(forwarding reference)  (0) 2022.08.31
[Modern C++] #2  (0) 2022.08.31
[Modern C++] #1  (0) 2022.08.31
[STL] algorithm  (0) 2022.08.31

+ Recent posts