Modern C++-正の値を参照
#include <iostream>
#include <vector>
#include <list>
#include <deque>
#include <map>
#include <set>
#include<algorithm>
using namespace std;
// Modern C++ (C++11 부터 나온 아이들)
// 오른값(rvalue) 참조와 std::move
// - Modern C++의 꽃이라고 할 수 있다.
class Pet {
};
class Knight {
public:
Knight() {
cout << "Knight()" << endl;
}
Knight(const Knight& knight) {
cout << "const Knight&" << endl;
}
~Knight() {
if (_pet)
delete _pet;
}
// 복사 대입 연산자
// 참고할 정보만 사용하고 인자는 변경 불가능
void operator=(const Knight& knight) {
cout << "operator=(const Knight&)" << endl;
_hp = knight._hp;
//_pet = knight._pet; // 펫을 공유한다? 말이 안되는데..
if (knight._pet)
_pet = new Pet(*knight._pet); // 깊은 복사가 필요
}
// 이동 대입 연산자
// 인자를 수정하거나 꺼내쓰거나 맘대로 하쇼. 안쓸거니께
void operator=(Knight&& knight) noexcept{
cout << "operator=(const Knight&&)" << endl;
// 얕은 복사
_hp = knight._hp;
_pet = knight._pet;
knight._pet = nullptr;
}
void PrintInfo() {
}
void CPrintInfo() const {
}
public:
int _hp = 100;
Pet* _pet = nullptr;
};
// 간단하긴 하지만 모든걸 복사해야하는 비효율과 원본을 넘겨주지 못하는 불편함이 있음
void TestKnight_Copy(Knight knight) {
knight._hp = 200;
}
// 불필요한 복사가 일어나지 않고 원본에 접근이 가능한 장점이 있음
// 사용설명서: Knight를 넘겨 줄테니 수정하든 꺼내쓰든 알아서해!
void TestKnight_LValueRef(Knight& knight) {
knight._hp = 200;
}
// const 참조값을 인자로 받기 때문에 rvalue 또한 인자가 될 수 있다.
// 하지만 인자로 받는 값은 수정이 불가능함
// 사용설명서: Knight를 넘겨 줄테니 수정하지말고 수정할 수 있는 모든 짓거리 불가!
void TestKnight_ConstLValueRef(const Knight& knight) {
// 또한 이 함수의 매개변수인 const Knight& knight는 변경될 수 없는 인자기 때문에
// 함수 내부에서 사용할 수 있는 knight의 멤버함수 또한 제한됨(const 선언이 되어있는 함수만 호출 가능)
// knight.PrintInfo(); // 불가!
knight.CPrintInfo(); // 가능!
}
// *오늘의 주제*
// 오른 값 참조를 받는 함수!
// 사용설명서: 읽고 쓰고 맘대로해 어차피 원본은 더이상 안쓸테니까
// -> 이동 대상, 원본 필요없어!
void TestKnight_RValueRef(Knight&& knight){
knight._hp = 200; // 수정도 가능
}
// 원본을 유지하지 않아도 되는 것의 장점은 뭘까?
//
int main()
{
// 왼값(lvalue) vs 오른값(rvalue)
// - lvalue : 단일식을 넘어서 계속 지속되는 개체
// - rvalue : lvalue가 아닌 나머지 (임시 값, 열거형, 람다, i++ 등)
int a = 3; // a는 지속되지만 3은 임시적으로 유효하다.
//3 = a; // 사용 불가
//a++ = 3; // 사용 불가
Knight k1;
TestKnight_Copy(k1);
TestKnight_Copy(Knight());
TestKnight_LValueRef(k1);
//TestKnight_LValueRef(Knight()); // 비const 참조값을 인자로 받는 함수는 rvalue를 인자로 넘겨줄 수 없다.
TestKnight_ConstLValueRef(Knight());// 함수 내부에서 변경하지 않는다는 조건이 걸려있기 때문에 rvalue를 넘겨줄 수 있다.
//TestKnight_RValueRef(k1); // 왼값 참조를 못받음
TestKnight_RValueRef(Knight()); // 오른값만 받을 수 있다.
TestKnight_RValueRef(static_cast<Knight&&>(k1)); // 강제로 k1을 rvalue로 변환하여 넘겨줌.
Knight k2;
k2._pet = new Pet();
k2._hp = 1000;
Knight k3;
// 'k2는 사용하고 버릴거야'라는 힌트를 줌, 이동 대입 연산자가 호출됨
k3 = static_cast<Knight&&>(k2);
k3 = std::move(k2); // 오른값 참조로 캐스팅
// std::move의 본래 이름 후보 중 하나가 rvalue_cast
// -> 이 친구는 사용하고 버릴 이동 대상이다.
// 속도차이가 꽤 난다
std::unique_ptr<Knight> uptr = std::make_unique<Knight>(); // 이 포인터는 딱 하나만 존재해야해
//std::unique_ptr<Knight> uptr2 = uptr; // 이 포인터의 복사를 막아둠
std::unique_ptr<Knight> uptr2 = std::move(uptr); // 이 포인터를 이제 니가 담당해. 나는 버려
return 0;
}
Reference
この問題について(Modern C++-正の値を参照), 我々は、より多くの情報をここで見つけました https://velog.io/@sansam41/Modern-C-오른값-참조テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol