묻공러
[C++ NOTE] Resource Move
묻공러
묻지마공부
묻공러
전체
오늘
어제
  • 분류 전체보기 (521) N
    • C (54)
      • [코드조선] C 핵심 (35)
      • [언어본색] C 기초 (19)
    • C++ (72)
      • [루키스] C++ (9)
      • [루키스] 콜백함수 (6)
      • [루키스] STL (8)
      • [루키스] Modern C++ (11)
      • [노코프] C++ (10)
      • [노코프] Tips (16)
      • [일지] C++ (12)
    • C# (20) N
      • [루키스] C# (9)
      • [루키스] 자료구조 (3)
      • [루키스] 실전 문법 (8) N
    • 자료구조 & 알고리즘 (50)
      • [코드조선] C 자료구조 & 알고리즘 (6)
      • [합격자되기] C++ 코딩테스트 (12)
      • [루키스] C++ 자료구조 & 알고리즘 (32)
    • CS (69)
      • [널널한 개발자] CS 개론 (19)
      • [혼자 공부하는] 컴퓨터 구조 (16)
      • [혼자 공부하는] 운영체제 (18)
      • [널널한 개발자] 네트워크 (16)
    • 게임 그래픽스 (46)
      • [전북대] OpenGL (25)
      • [일지] DirectX (21)
    • 게임 엔진 - 언리얼 (123)
      • [코드조선] 언리얼 (53)
      • [코드조선] 언리얼 데디서버 (8)
      • [일지] 언리얼 (59)
      • [일지] 언리얼 (2) (3)
    • 게임 엔진 - 유니티 (14) N
      • [최적화] 유니티 (4)
      • [루키스] 유니티 (10) N
    • 게임 서버 (17)
    • 게임 수학 & 물리 (19)
      • 게임 수학 (12)
      • 게임 물리 (7)
    • GIT & GITHUB (4)
    • 영어 (18)
      • [The Outfit] 대본 공부 (11)
      • the others (7)
    • 그 외 (14)
      • In (5)
      • Out (5)
      • Review (4)

인기 글

최근 글

hELLO · Designed By 정상우.
C++/[노코프] C++

[C++ NOTE] Resource Move

2024. 3. 26. 12:10

01. Pointer vs. Reference

값, 포인터, 참조를 통해 전달하는 3가지 방식이 존재한다

값으로 전달을 하면 데이터를 전체 다 복사해야 한 경우가 발생한다

따라서, 포인터와 참조를 통해 전달하는 것이 효율적이다

둘의 차이는 내부적으로 없으며

참조의 경우는 const와 함께 작성해서 값을 변경하지 못하도록 막는 경우가 많다

void fooV(std::array<int,100> a)
{
	int b = a+1;
};

void fooP(int * ap)
{
	int b = *ap+1;
};

void fooR(const int & a)
{
	int b = a+1;
	a =100;
};

 



02. L-Value vs. R-Value

# L-Value vs. R-Value

R-Value는 한 번만 사용되고 더 이상 불려지거나 사용되지 않는 경우

L-Value는 계속 재사용되고 불려지는 경우

 

# Value vs. L-Value Ref vs. R-Value Ref

#include <string>

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

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

void storeByRRef(std::string && s)
{
	//std::string b = s;// s가 계속 재사용될 수 있기 때문에
	std::string b = std::move(s);
};

int main()
{
	std::string a = "abc";
    
	storeByValue(a);
    
	storeByLRef(a);
    
	//storeByRRef(a);// 오류가 발생한다
	storeByRRef(std::move(a));// 1번 해결방식
	storeByRRef("abc");// 2번 해결방식

}

 

위의 예제에서

Value를 이용하면, 2번 Copy

LRef를 이용하면, 1번 Copy

RRef를 이용하면, 0번 Copy가 일어난다

 



03. std::move()

# move

std::move는 소유권을 넘겨주면서

Lvalue를 Rvalue로 바꿔주는 것이다

 

# move 예시 1

"abc"에 대한 소유권이 a에서 b로 넘어갔기 때문에

마지막 줄에서 a는 출력되지 않는다 

#include <string>
#include <iostream>

int main()
{
	std::string a = "abc";
	std::cout << a << std::endl;

	std::string b = std::move(a);
	std::cout << b << std::endl;
	std::cout << a << std::endl;
    
}

 

# move 예시 2

LRef함수에서 s(a)에대한 소유권이 b로 넘어갔기 때문에

마지막 줄에서 a는 출력되지 않는다

#include <string>
#include <iostream>

void storeByLRef(std::string& s)
{
	std::string b = std::move(s);
};

void storeByRRef(std::string&& s)
{
	std::string b = std::move(s);
};

int main()
{
	std::string a = "abc";
	storeByLRef(a);
	std::cout << a;
}

 

# move 예시 3

예시 2에서 LRef 함수에서는 Copy가 0번이지만

예시 3에서 처럼 LRef 함수의 인자에 const를 붙여주면

Copy가 발생한다

그래서 a가 정상적으로 출력된다

#include <string>
#include <iostream>

void storeByLRef(const std::string& s)// const를 추가
{
	std::string b = std::move(s);
};

void storeByRRef(std::string&& s)
{
	std::string b = std::move(s);
};

int main()
{
	std::string a = "abc";
	storeByLRef(a);
	std::cout << a;
}


# 그럼 뭘써야하나?

Lval는 Copy 1번

Rval는 Copy 0번이 최상의 효율이고

이를 위해서는 인자에 값을 받고 함수 내부에서 std::move를 이용하면 된다

#include <string>
#include <iostream>

class Cat
{
public:
	void setName_1(std::string name)// Lval Copy 2번 발생
	{
		mName = name;
	};

	void setName_2(std::string && name)// Lval를 받지 못해 컴파일 에러
	{
		mName = std::move(name);
	};

	void setName_3(std::string & name)// Rval Copy 0번 발생하지만, Lval s는 소유권이 사라짐
	{
		mName = std::move(name);
	};

	void setName_4(const std::string & name)// Lval Copy 1번, Rval Copy 1번
	{
		mName = std::move(name);
	};

	void setName_5(std::string name)// Lval Copy 1번, Rval Copy 0번 (최고 효율)
	{
		mName = std::move(name);
	};
private:
	std::string mName;
};

int main()
{
	Cat kitty;
	std::string s = "kitty";
	kitty.setName_5(s); // 1 copy 
	kitty.setName_5("nabi");//0 copy, Copy elision을 통해 nabi는 복사되지 않음

}

 



04. RVO

# RVO 개념
Return Value Optimization은 리턴하는 값의 최적화를 해주는 기능이다

따라서 return 값에 move 사용하지 않아도 된다

 

# RVO 예시 1

#include <string>

std::string getString()
{
 	std::string s = "no";
    
 	//return std::move(s);// 해줄 필요 없음
 	return s;// RVO
}

int main()
{
	std::string a = getString();

	return 0;
}

 

위의 예제에서

RVO는

"no"라는 문자열이 Copy 되지 않게 하고

처음부터 s를 없는 취급 해서

소유권이 이동(move) 조차도 일어나지 않고

바로 a에 "no"를 연결시키는 작업을 한다

 

# RVO 예시 2 - Move Constructor

#include <string>

 std::string getString(std::string a, bool b)
 {
	if (b)
	{
		a = "no";
	}

 	return a; // RVO 개입 X
	// return std::move(a);// Move Constructor로 Copy가 발생 안하니 작성 필요 없음
}

int main()
{
	std::string a = getString("abc", 1);// Move Constructor

	return 0;
}

 

위의 예제처럼

컴파일러가 복사된 a를 돌려줘야 할지 a에 바로 "no"를 연결해 줄지 알 수 없는 경우에는

RVO가 개입되지 않는다

 

그러나, RVO가 개입되지 않아도

이동 생성자가 실행이 되었기 때문에 Copy는 발생하지 않고

std::move를 return 값에 작성해주지 않아도 된다

 

# Copy Constructor vs. Move Constructor

#include <string>

int main()
{
	std::string s = "abc";
	std::string b = s;// Copy Constructor

	std::string c = std::move(s);// Move Constructor
	// Lvalue인 s가 Rvalue로 move되면서
	// 소유권이 c에게 넘어가고 zero copy가 일어나며 
	// 복사 없이 소유권이 넘어가는 복사 생성자가 실행

	return 0;
}
저작자표시 비영리 변경금지 (새창열림)

'C++ > [노코프] C++' 카테고리의 다른 글

[C++ NOTE] Smart Pointer  (0) 2024.03.29
[C++ NOTE] Inheritance  (0) 2024.03.28
[C++ NOTE] OOP  (0) 2024.03.27
[C++ NOTE] Compile Process  (0) 2024.03.25
[C++ NOTE] Memory Structure  (0) 2024.03.24
'C++/[노코프] C++' 카테고리의 다른 글
  • [C++ NOTE] Inheritance
  • [C++ NOTE] OOP
  • [C++ NOTE] Compile Process
  • [C++ NOTE] Memory Structure
묻공러
묻공러
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.