WinCNT

decltype과 Value Category(lvalue, rvalue, xvalue) 본문

게임 프로그래밍(학습 내용 정리)/Modern C++

decltype과 Value Category(lvalue, rvalue, xvalue)

WinCNT_SSS 2022. 3. 24. 14:03

lvalue(L-Value) - 변수

prvalue(Pure R-Value) - 순수(pure) rvalue

xvalue(eXpiring value) - 소멸하는 값

 

glvalue = lvalue + xvalue

주소가 있는 것, 정체가 있는 것, 보관하고 있는 것

참조하기 위해서는 lvalue 참조자 &

 

rvalue = prvalue + xvalue

이동시킬 수가 있으면 rvalue

참조하기 위해서는 rvalue 참조자 &&

move 함수(move semantics)
  우측값 레퍼런스를 통해서, 기존에는 불가능하였던 우측값에 대한 (복사가 아닌) 이동의 구현이 가능해졌다.
  좌측값도 이동을 시키고 싶다면 어떨까?
  C++ 11 부터 <utility> 라이브러리에서, 좌측값을 우측값으로 바꾸어주는 move 함수를 제공

 

std::move 함수는 이동을 수행하지 않는다. 그냥 인자로 받은 객체를 우측값으로 변환할 뿐이다.
이동 자체는 std::move 를 실행함으로써 발생하는 것이 아니라, 
우측값을 받는 함수들이 오버로딩 되면서 수행되는 것.

class A {
public:
	A() { std::cout << "일반 생성자 호출!" << std::endl; }
	A(const A& a) { std::cout << "복사 생성자 호출!" << std::endl; }
	A(A&& a) { std::cout << "이동 생성자 호출!" << std::endl; }
};

int main() {
	A a;

	std::cout << "---------" << std::endl;
	A b(a);

	std::cout << "---------" << std::endl;
	A c(std::move(a));
}

이동 생성자가 필요한 예

함수 안에서 어떤 변수를 만들고, 그 변수를 인자로  다른 함수를 호출할 때

그 변수는 쓰고 버려질 것이기 때문에 이동 생성자를 쓰면 속도적으로 매우 효율적이다

#include <iostream>
#include <string>
#include <vector>
using namespace std;

/// <summary>
/// 복사 생성자와 복사 대입 연산사
///		T(const T& p);
/// 
/// 복사 생성자가 사용되는 경우
/// 1. 객체의 선언 및 초기화: A a(b);
/// 2. 객체의 값에 의한 전달: 
/// 3. 객체의 값에 의한 반환: A F() {  }
/// 
/// 
/// 이동 생성자
///		T(T&& a) [noexcept];
///		이동 생성자는 호출되면 얕은 복사(shallow copy)를 하고 원본의 소유권을 대상으로 이전(move)하고
///		원본 객체를 nullptr로 초기화하여 접근할 수 없게 만든다
///		(나중에 delete 처리를 안 해도 됨)
///		이동 생성자와 복사 생성자를 모두 구현하면, 코드 상황에 따라 복사 혹은 이동이 된다
/// 
/// 번외) noexcept
///		이동 생성자는 주소가 없어지기 때문에 주소 이전 도중에 예외를 발생시키면
///		복구가 불가능하게 되므로, 문제가 생긴다
/// 
/// 이동 생성자의 호출 조건
///		1. 임시 객체를 전달할 때
///		2. std::move()를 사용하여 인자를 rValue 참조자로 변환하여 전달할 때
/// 
/// 이동 생성자 및 이동 할당 연산자를 작성하면,
///		적은 복사, 메모리 할당 및 메모리 할당 취소 작업을 수행하기 때문에 효율적이다
/// 
/// 클래스를 설계할 때,
///		복사 생성자를 안 만들고 이동 생성자만 만들 수도 있으며, 그 반대도 가능하다
/// 
/// 번외) explicit
///		
/// </summary>
/// <returns></returns>

class A
{
public:
	A()				{ cout << "일반 생성자 호출!" << endl; }
	A(const A& a)	{ cout << "복사 생성자 호출!" << endl; }
	A(A&& a)		{ cout << "이동 생성자 호출!" << endl; }

	A& operator=(const A& rhs)
	{
		if (this != &rhs)
		{
			cout << "복사 대입 연산자" << endl;
		}
	}
};

class B
{
public:
	//B(A a) { }
	B(const A& a) : m_a(a) {}
	B(A&& a) : m_a(move(a)) { }
	A m_a;
};

int main()
{
	A a;
	A a2(a);
	A a3(move(a));

	cout << "Create B\n";

	//B b1(a);
	//B b2(a);
	B b3(move(a));
}

 

SSS

'게임 프로그래밍(학습 내용 정리) > Modern C++' 카테고리의 다른 글

배열 포인트와 _countof(혹은 ARRAYSIZE)  (0) 2022.06.14
스마트 포인터 - unique_ptr  (0) 2022.04.21
스마트 포인터  (0) 2022.04.14
범위 기반 for문  (0) 2022.03.24
Modern C++ - Auto  (0) 2022.03.24