C++ Resource Move

LeemHyungJun·2022년 9월 15일
0

C++ Study

목록 보기
2/12
post-thumbnail

Pointer vs Reference

  • pointer가 무조건 필요한 경우가 아니라면 reference 쓰는 것이 좋다.
#include<vector>

void fooV(int a) //pass by value
{
	int b = a + 1;
}

void fooP(int* ap) //pass by pointer
{
	int b = *ap + 1;
	*ap = 100;
}

void fooR(const int& ar) //pass by reference
						 //값 변경 없으므로 const 쓰기
{
	int b = ar + 1;
}

int main()
{
	int a = 0;
	fooV(a);
	fooP(&a);
	fooR(a);
    
	return 0;
}

L-value vs R-value

  • l-value, r-value 구별 코드
int a = 0;
int b = a;
std::string s = "abc";
int c = std::move(a); //l-value가 r-value로 변함
  • l- value : a, b, a(아래줄의 a), s, c
  • r- value : 0, "abc", std::move(a)
    => 한번 부르고 다시 부를 수 있다면 l-value

========================================

  • r-value와 move를 통한 copy를 줄이는 코드
#include<string>

void storeByValue(std::string s) //2 copy
{
	std::string b = s;
}

void storeByLRef(std::string& s) //1 copy
{
	std::string b = s;
}

void storeByRRef(std::string&& s) //0 copy
{
	//std::string b = s; //wrong! s는 해당 경우 lvalue이다.
	std::string b = std::move(s); //ok!
}
int main()
{
	std::string a = "abc";
	storeByValue(a);
	storeByLRef(a);
	storeByRRef("abc");
}
  • 위 코드의 동작을 표현한 그림

std::move

  • std::move의 resource ownership 넘겨주는 코드
#include <iostream>
#include <string>

int main()
{
	std::string a = "good C++";
    std::cout<<"a : "<< a << std::endl;
    std::string b = std::move(a);
	std::cout << "b: " << b << std::endl;
    
	//std::move를 통해 ownership을 b에게 넘겨줌
	std::cout << "a: " << a << std::endl; //아무것도 출력 x
    
    return 0;
}
  • std::move의 사용(아무때나 쓰지 말기)
#include <string>
#include <iostream>

void storeByLRef(const std::string& s)
{
	std::string b = std::move(s); // copy 발생 -> bad
    std::cout<< "b : " << b <<std::endl;
}

int main()
{
	std::string a = "abc";
	storeByLRef(a); 					  // b : abc
	std::cout << "a: " << a << std::endl; //a : abc
}
  • std::move를 잘 사용하는 코드 (효율적인 사용을 찾기)
    -> l-value를 주면 1 copy r-value를 주면 0 copy가 가장 이상적
#include<string>
#include<iostream>

class Cat
{
public:
	void SetName1(std::string name)
	{
		mName = name;
	}
	void SetName2(std::string &&name) 
	{
		mName = std::move(name);
	}
	void SetName3(const std::string& name) //const!!
	{
		mName = std::move(name);
	}
	void SetName4(std::string name) //가장 좋은 방식!!
	{
		mName = std::move(name);
	}
private:
	std::string mName;
};

int main()
{
	Cat kitty;
	std::string s = "kitty";

	kitty.SetName1(s);//l-value 넘겨줌//2 copy
	kitty.SetName1("nabi");//r-value 넘겨줌

	//kitty.SetName2(s); //compile error : l-value를 파라메터로 받지 못함
	//kitty.SetName2("nabi");

	kitty.SetName3(s); //1 copy 
    //->"kitty" 의 소유권이  mName으로 넘어가고 s에는 아무것도 남지 않는 것을 방지하기 위해 const 사용
	kitty.SetName3("nabi"); //1 copy 

	kitty.SetName4(s); //1 copy
	kitty.SetName4("nabi"); //0 copy (copy elision)-> 컴파일러 최적화

}
  • 위 코드에서 파라메터는 value로 받고 std::move를 사용하는 SetName4() 의 구조

RVO (Return Value Optimization)

  • Copy ellision : 파라메터를 value로 받았을때 optimization 되는 경우
  • RVO와 RVO 개입하지 않는 경우의 코드
#include<string>

std::string getString() //RVO 개입
{
	std::string s = "good"; //RVO를 통해 
							//0 copy 
							//0 move 
	return s;
}

std::string getString2(std::string a,bool b) //RVO 개입x
{
	if (b)
	{
		a = "good";
	}
	return a; //RVO 개입 x(복사 할지, 바로 string을 가리키게 할지 모름)
	//그럼에도 불구하고..move constructor에 의해 0 copy
}

int main()
{
	std::string a = getString(); //move constructor 실행

	return 0;
}
  • RVO가 없다고 가정할 때 작동 모습과 RVO의 작동 모습

0개의 댓글