[C++]R-value Reference,move Sementics

2021. 2. 20. 21:18Study/C&C++

 R-value Reference,move Sementics

C++ 에서는 R-value Reference 를 지원한다.

다음과 같이 &&기호를 이용하여 사용할 수 있다. 

#include <iostram>
using namespace std;

void doSomething(int& lef)
{
	cout << "l-reference" << endl;
}
void doSomething(int&& ref)
{
	cout << "r-reference" << endl;
}
int getResult(){return 1;}

int main()
{
	int x = 1;
    int &&rref = 5; //r-value reference
    rref = getresult();
    doSomething(x);
    dosomething(1);
    dosomething(getresult());
    return 0;
}

compiler는 r-value와 l-value 를 다르게 인식 하여 함수 오버로딩 또한 가능하다.

하지만, 왜? 굳이  r-value reference를 지원할까? r-value reference로 얻는것은 무었일까? 

 

 move semantics

한 Resource 에 대한 포인터를 담고 있는 AutoPtr 클래스가 있다. 

 AutoPtr 클래스의 복사 생성자, 할당 연산자(=) 를 일반적으로 구현 한다면.

AutoPtr(const AutoPtr& input)
{
	//deep copy more slower
	std::cout << "AutoPtr copy constructor" << std::endl;
    //construct new object
	m_ptr = new T;
    //deep copy
    //call assignment operator(=) of input
	*m_ptr = *input.m_ptr;
}
AutoPtr& operator = (const AutoPtr& input)
{
	std::cout << "AutoPtr copy assignment" << std::endl;
	if (&input == this)
	{
		return *this;
	}
	if (m_ptr != nullptr) delete m_ptr;
    //construct new object
	m_ptr = new T;
    //deep copy
	//call assignment operator(=) of input  
	*m_ptr = *input.m_ptr;
	return *this;
}

이와 같이 l-value 로 구현 되었을 것이다. 

auto doSomething()
{
	AutoPtr<Resource2<int>> res= new Resource2<int>(100000000);
	return res;
}
int main()
{
	AutoPtr<Resource2<int>>  res_;
	res_ = doSomething();
}

 

이럴때 res_ 가 큰 Resource 를 가리키는 Autoper를 return 값으로 받을때

AutoPtr res_의 할당 연산자(=) 에서 새로운 Resourc2 객체가 생성되고

Resource2 의 할당연산자(=)를 통하여 Deep Copy가 일어난다.

 

하지만 이런 과정은 굉장히 비효율적이다.

단순히 doSomething()에서 생성된 Resource2를 가리키는 AutoPtr Class만 바꿔주면 되는데

새로운 Resource2를 만들어 내용 복사(Deep Copy)까지 해주기 때문이다. 

 

이와같은 비효율을 해결 하는 것이 move Sementics 이다.

 

AutoPtr(AutoPtr&& input)
{
	std::cout << "AutoPtr move constructor" << std::endl;
	//shallow copy
	m_ptr = input.m_ptr;
	input.m_ptr = nullptr;
}
AutoPtr& operator = (AutoPtr&& input)
{
	std::cout << "AutoPtr move assignment" << std::endl;
	if (&input == this)
	{
		return *this;
	}
	if (m_ptr != nullptr) delete m_ptr;
	//shallow copy
	m_ptr = input.m_ptr;
	input.m_ptr = nullptr;
}

 

이처럼 R-value로 인자를 받고 없어질 예정인 인스턴스에 대한 소유권만 넘겨준다.(shallow copy)

 

또한 당연히 수행 시간도차이가 있다. 

C++ 에서 이런 move Sementics를 이용하기위해 Std::move 를 제공한다. 

template <typename T>
void mySwap(T& a, T& b)
{
	T temp = std :: move(a);
	a = std::move(b);
	b = std::move(temp);
}

이를 이용하여 move sementic의 장점을 활용한 swap함수를 만들어 낼 수 있다.

 

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

[C++] 다형성,virtual 함수  (2) 2021.03.03
[C++] std::cin, getline()  (0) 2021.02.22
[C++] l-value,r-value  (0) 2021.02.14
[C++] C -style string , std::string  (0) 2021.02.11
[C++] Stack and Heap(feat. Memory Leak)  (0) 2021.02.11