C++/기타

[C++] LValue vs RValue (3)

sseram 2023. 5. 15. 14:22
반응형

2023.05.16 - [C++] - [C++] LValue vs RValue. 총 정리

2023.05.10 - [C++/기타] - [C++] LValue vs RValue (2)

 

[C++] LValue vs RValue (2)

2023.04.29 - [C++/기타] - [C++] lValue vs rValue (1) [C++] LValue vs RValue (1) 맨 첨에 C를 어정쩡하게 배운 후에 C++ 사용하다 보니 애매하게 이해가 되기도 했고.. 지금도 어느 정도 쓰고 있긴 하지만 아직까지

donot-simsim.tistory.com

 

에서 이어지는 글.

 

 

value. glvalue와 rvalue의 특성을 모두 가지고 있다.

 

xvalue. [곧 사라지는 값] 이 가지고 있는 두 가지의 특성

 

 

1. 본인이 고유한 주소를 가지고 있다는 점.

2. 그 값을 이동 시킬 수 있다는 점.

 

 

 

에서 2 번째 특징을 예시 코드를 통해 정리해 보았다.

 

 


 

#include <iostream>
#include <vector>

using namespace std;

string getName(int i) {
	if (i == 1) {
		return string("someName");
	} else {
		return string("error");
	}
}

int main() {
	string name = getName(1);

	cout << name << endl;

	return 0;
}

 

상당히 자주 사용되는 함수 형태이다.

함수를 통해 원하는 값을 얻어 와 변수에 저장하는 형태. 이 때의 getName의 return 값은 xvalue 형식이다.

 

getName(1)이라는 함수의 값은 1번 특성으로 인하여 본인의 고유한 주소값을 가지고 있다는 것을 이미 알고 있다.

그렇다면 넘어왔을 때 이 값을 어떻게 사용하여 string name 이라는 변수에 넘겨 줄까?

 

 

 

 

#include <iostream>
#include <vector>

using namespace std;

class myClass {
public:
	int mynum;
	myClass() {
		mynum = 0;
		cout << "default constructor" << endl;
	}

	myClass(int a) {
		mynum = a;
		cout << "default constructor with " << a << endl;
	}

	myClass(const myClass& obj) {
		mynum = obj.mynum;
		cout << "copy constructor" << endl;
	}

	myClass& operator=(const myClass& obj) {
		this->mynum = obj.mynum;
		cout << "copy assign constructor" << endl;
		return *this;
	}

	myClass(myClass&& obj) noexcept {
		this->mynum = obj.mynum;
		cout << "move constructor" << endl;
	}

	myClass& operator=(myClass&& obj) noexcept {
		this->mynum = obj.mynum;
		cout << "move assign constructor" << endl;
		return *this;
	}

	~myClass() {
		cout << "destructor " << mynum << endl;
	}
};

 

해당 부분을 확인하기 위하여, 생성자가 호출 될 때 어떤 생성자가 호출되는지 알 수 있게 print 찍어주는 myClass를 하나 만들었다. 다만 각각의 생성자 내부에서 효율적으로 돌기 위하여 이동, 복사 등 본연의 역할을 다 해야 하지만, ( ex) 내부 변수가 primitive type이 아니라 vector/ string 등.  이동 시에 포인터 값을 옮겨주고 본인은 delete... ) 해당 부분은 패스하고 어떤 생성자가 호출된 상황인지 print만 찍어 주었다.

 

 

 

 

먼저 간단하게 위의 class를 사용하여 프로그램을 구현해 보았다.

int main() {
	myClass m1class(4);
	myClass m2class(5);

	cout << "-----------------------------------" << endl;

	m1class = m2class;

	cout << m1class.mynum << endl;

	return 0;
}

m1class, m2class가 기본 생성자로 만들어진다.

m2class = m1class를 할 때 m1class에 있던 값이 copy되어 m2class로 들어가게 되고, m2class 내부의 값은 5로 변경된다. 

 

 

 

그리고 위 함수를 살짝 다르게 변경해 보았다.

 

myClass makemyClass() {
	return myClass(5);
}

int main() {
	myClass m1class(4);

	cout << "-----------------------------------" << endl;

	m1class = makemyClass();

	cout << m1class.mynum << endl;

	return 0;
}

위 코드와 비슷한 상황이지만, 직접 만들어서 넣지 않고 함수를 통하여 myclass를 얻어 온 후 assign 시켜 주었다. 이 때는 copy가 아닌 move가 호출되었다.

 

 


 

 

사실 m1class = m2class 에서 m2class는 const myClass& 에 묶여서 copy assign operator으로 가고,

m1class = makemyClass()에서 makemyClass()는 myClass&& 가 되어 각각에 맞는 move assigne operator에 들어간 거지만.. 여기선 참조를 빼 두고 설명해보자.

 

다시 한 번, 이런 못생긴 메모리가 있다.

 

 

복사는 말 그대로 복사이다. 내가 가지고 있는 값과 같은 값을 상대방에게 알려주어서, 상대방이 그 값을 가질 수 있게 한다.

만약 본인이 한 값(ex) vector<string> vecstr)을 가지고 있고, 상대방에 복사를 해 갔다면 그 값은 메모리 상에 두 개가 존재하게 된다.

요래

 

 

 

 

 

 

이동은 값을 상대방에게 주는 것이다. 내가 가지고 있는 값의 소유권을 넘기고, (보통) 넘겨준 object는 소멸해 버린다. 즉 해당 값은 메모리 상에 한 개만 존재하게 된다.

요래

 

 

 

위의 코드 상황에서 m1Class = m2class 라는 코드를 수행 할 때, m2class는 자신의 값을 복사해 주어야 하지, 이동하면 본인의 값이 사라지기 때문에 이동해줄 수 없다. 가능은 해도, m2Class라는 값은 이동해 준 이후부터 사용이 불가능하다.

더보기

가능은 하다. m1class = std::move(m2class);

다만 이 방법이 모두에게 먹히는 것은 아니고, 먹힌다고 하더라도 그 값 자체가 moveable 하진 않고, 특수한 처리를 해 주어야 moveable 해 진다.

 

 

다만 m1class = makemyclass() 상황에서는 함수를 통해 만든 값이 어차피 곧 사라지는 값 (eXpring value)이기 때문에 이동을 해도 아무런 문제가 없다. 즉 그 값 자체로 이동 가능하다.

 

 

 


 

결국.

xvalue는 값을 이동 시킬 수 있다.

 

 

 

 

 

 

이렇게 정의를 내리고, 위 표를 다시 한 번 보니 1번에서 했던 정리가 뭔가 좀 어색해 보인다. glvalue와 rvalue에 대한 새로운 정의가 필요할 것 같다.

 

 

https://donot-simsim.tistory.com/58

사실, 1번에서 했던 정리는 약간 고전적인 방식의 lvalue, rvalue 분류라고 한다.

 

요즘에는, xvalue의 특징이었던

 

- 본인의 고유한 주소를 가지고 있다.

- 값이 moveable 하다.

 

이 두개를 가지고 다시 분류를 한다고 한다.

 

 

이 부분은 다음 포스팅에서..

 

2023.05.16 - [C++] - [C++] LValue vs RValue. 총 정리

 

[C++] LValue vs RValue. 총 정리

2023.04.29 - [C++/기타] - [C++] LValue vs RValue (1) [C++] LValue vs RValue (1) 맨 첨에 C를 어정쩡하게 배운 후에 C++ 사용하다 보니 애매하게 이해가 되기도 했고.. 지금도 어느 정도 쓰고 있긴 하지만 아직까지

donot-simsim.tistory.com

 

 

 

*잘못된 정보는 알려주시면 감사한 마음으로 수정하겠습니다.

반응형