이전 정리글
2022.01.06 - [프로그래밍/C/C++] - C++ rvalue reference (우측값 참조) move semantics
우측값(rvalue)은 함수의 인자로 넘어갈 때 우측값 참조자(rvalue reference) 뿐만이 아니라 const 타입의 좌측값 참조자(lvalue reference)로도 넘겨질 수 있다. 같은 함수가 존재할 경우 우측값 참조자의 우선순위가 더 높다.
이번 정리는 우측값 참조의 속성에 대해서 알아보자. 우선 예제 코드를 보자.
#include <iostream>
#include <vector>
using namespace std;
class clsObject
{
public:
clsObject(size_t sz) {
mSize = sz;
mData = new uint8_t[sz];
}
~clsObject() {
if (mData != nullptr) {
delete[] mData;
}
}
private:
size_t mSize;
uint8_t* mData;
};
void func(const clsObject& cls)
{
wcout << "const clsObject& cls" << endl;
}
void func(clsObject&& cls)
{
wcout << "clsObject&& cls" << endl;
}
int main()
{
clsObject obj(10);
func(obj);
func(clsObject(12));
return 0;
}
위 코드를 보면 동일한 func 이 존재하며 위에 함수는 좌측값 참조를 아래 함수는 우측값 참조를 인자로 사용하고 있다. main 에서 func 함수 호출 시 obj 를 인자로 넘긴 func 는 lvalue 가 전달되었기에 위에 함수가 호출되며 두번째 func() 는 clsObject(12) rvalue 이기에 우측값 참조를 인자로 사용하는 func 이 호출된다. 여기서 유의해야 할 점은 인자가 rvalue 일 경우 첫번째, 두번째 func 모두 호출될 수 있다. 왜냐하면 첫번째의 좌측값 참조 앞에 const 가 붙었으므로 rvalue 도 받을 수 있다. 하지만 && 표현식의 우선 순위가 높기 때문에 후자의 func() 가 호출된다.
좌측값(lvalue)은 우측값 참조자(rvalue reference) 타입으로 캐스팅될 수 있다.
다음 예제 코드를 보자.
#include <iostream>
#include <vector>
using namespace std;
class clsObject
{
public:
clsObject(size_t sz) {
mSize = sz;
mData = new uint8_t[sz];
}
~clsObject() {
if (mData != nullptr) {
delete[] mData;
}
}
private:
size_t mSize;
uint8_t* mData;
};
void func(const clsObject& cls)
{
wcout << "const clsObject& cls" << endl;
}
void func(clsObject&& cls)
{
wcout << "clsObject&& cls" << endl;
}
int main()
{
clsObject obj(10);
func(obj);
func(static_cast<clsObject&&>(obj));
func(std::move(obj));
return 0;
}
위의 코드를 보면 알 수 있는 것은 좌측값은 우측값 참조로 type casting 될 수 있다는 것을 보여준다. std::move 함수는 강제로 우측값 참조로 type casting 해주는 역할을 하는 함수이다.
우측값 참조자(rvalue reference) 타입의 함수 인자 변수 자체는 함수 내부에서 좌측값(lvalue)이다.
세번째 코드를 보도록 하자.
#include <iostream>
#include <vector>
using namespace std;
class clsObject
{
public:
clsObject(size_t sz) {
mSize = sz;
mData = new uint8_t[sz];
}
~clsObject() {
if (mData != nullptr) {
delete[] mData;
}
}
private:
size_t mSize;
uint8_t* mData;
};
void func(clsObject&& cls)
{
wcout << "clsObject&& cls" << endl;
}
clsObject&& func2(clsObject&& cls)
{
return std::move(cls);
}
int main()
{
clsObject obj(10);
func(func2(std::move(obj)));
return 0;
}
위 코드에서 보여주는 것은 무엇인가? func2 함수는 우측값 참조(rvalue reference)를 반환하고 있으며 인자로 또한 우측값 참조(rvalue reference)를 받고 있다. 그런데 함수 내부에서 들어온 인자에 대해서 std::move 를 해주고 있다. 왜인가? 그렇다. 들어온 인자의 타입 자체는 우측값 참조(rvalue reference)이나 넘어온 인자 변수 cls 자체는 좌측값(lvalue) 이기 때문이다.
다음 정리글은
2022.01.07 - [프로그래밍/C/C++] - C++ Universal reference & Reference Collapsing Rules
'프로그래밍 > C/C++' 카테고리의 다른 글
C++ Perfect forwarding (std::forward 의 역할) (0) | 2022.01.08 |
---|---|
C++ Universal reference & Reference Collapsing Rules (0) | 2022.01.07 |
C++ rvalue reference (우측값 참조) move semantics (0) | 2022.01.06 |
C++ Lvalue (좌측값) Rvalue (우측값) Rvalue reference (우측값 참조자) (0) | 2022.01.05 |
C++ lambda expression 람다 표현식 (0) | 2022.01.04 |