string b = std::move(a);
a에 Lval가 오는 경우와 Rval 가 오는 경우
--
std::move 함수는 인자로 받은 객체를 rvalue reference로 캐스팅하는 유틸리티 함수입니다. 이 함수는 객체의 데이터를 실제로 이동시키지 않으며, 단지 해당 객체를 이동할 수 있는 상태로 만듭니다. 그렇게 함으로써 이동 생성자(move constructor)나 이동 할당 연산자(move assignment operator)가 호출될 수 있게 합니다. 이러한 이동 연산자들은 객체의 내부 리소스(예: 동적 할당된 메모리)의 소유권을 효율적으로 새 객체로 이전하는 데 사용됩니다.
std::move가 호출될 때 인자로 Lvalue가 오는 경우와 Rvalue가 오는 경우에 대해 설명하겠습니다:
- Lvalue가 std::move에 전달된 경우: Lvalue는 이름이 있는 객체를 참조합니다 (예: 변수 a). std::move(a)는 a를 rvalue reference로 캐스팅합니다. 이는 a가 이동 가능한 상태임을 나타내며, 이후에 a를 대상으로 이동 생성자나 이동 할당 연산자가 호출될 수 있습니다. 이동 연산이 수행되면 a의 내부 리소스는 새로운 객체 b로 이전되고, a는 빈 상태나 정의되지 않은 상태가 됩니다.
- Rvalue가 std::move에 전달된 경우: Rvalue는 이름이 없는 임시 객체를 참조합니다 (예: 함수에서 반환되는 임시 객체). Rvalue는 이미 이동 가능한 상태이므로 std::move를 사용할 필요가 없습니다. 그러나 std::move를 사용하여 Rvalue를 명시적으로 rvalue reference로 캐스팅하는 것은 문제가 되지 않으며, 이 경우에도 이동 생성자나 이동 할당 연산자가 호출될 수 있습니다.
두 경우 모두, std::move는 객체를 이동할 준비가 되었다는 신호를 보내는 역할을 하며, 실제 이동 작업은 이동 생성자나 이동 할당 연산자에 의해 수행됩니다. 이때 중요한 점은 std::move를 호출한 후에는 원본 객체를 더 이상 사용하지 않거나, 값을 재할당하거나 파괴하기 전까지는 접근하지 않는 것이 좋다는 것입니다. 이는 원본 객체가 더 이상 유효한 상태가 아닐 수 있기 때문입니다.
std::move()
ex)
string b = std::move(a);
a 라는 Lval 를 Rval로 변환시켜
a의 값에 대한 소유권을 b 에게 넘긴다.
#include <iostream>
using namespace std;
void rf_argu(string& s)
{
string b = std::move(s);
};
void noraml_argu(string s)
{
string b = std::move(s);
};
class Foo
{
private:
string nName;
public:
void SetName(string name)
{
nName = std::move(name);
}
};
int main()
{
cout << "---------------------" << endl;
int a = 1;
cout << a << endl; // 출력값 : 1
int c = std::move(a); // 내장 타입(primitive type)의 경우, 이동 시맨틱이 적용 되지 않음
cout << a << endl; // 출력값 : 1
cout << c << endl; // 출력값 : 1
string q = "qqq";
cout<<q<<endl; // 출력값 : qqq
string w = std::move(q); // 클래스 타입(class type)의 경우, 이동 생성자(move constructor)나 이동 대입 연산자(move assignment operator)가 정의되어 있어 이동 시맨틱이 적용됨
// move() 키워드로 Lval를 Rval로 바꾸면서 resource ownership 을 다른 obj에 넘긴다.
cout<<q<<endl; // 출력값 :
cout<<w<<endl; // 출력값 : qqq
cout << "---------------------" << endl;
string t_1 = "aaaaaaaaa";
cout << t_1 <<endl; // 출력값 : aaaaaaaaa
rf_argu(t_1); // 참조에 의한 전달은 t_1 자체를 넘기므로 소유권이 이전되 출력값이 없음
cout << t_1 <<endl; // 출력값 :
cout << "---------------------" << endl;
string t_2 = "aaaaaaaaa";
cout << t_2 <<endl; // 출력값 : aaaaaaaaa
noraml_argu(t_2); // 값에 의한 전달은 복사본을 넘기기 때문에 t_2 의 소유권이 이전되지 않음
cout << t_2 <<endl; // 출력값 : aaaaaaaaa
cout << "---------------------" << endl;
Foo foo;
string s = "foo";
foo.SetName(s); // Lval 를 넘긴 경우 1 copy
foo.SetName("bar"); // Rval 를 넘긴 경우 0 copy
cout << s << endl;
}
'언어 정리 > C++_개념_lib' 카테고리의 다른 글
디폴트 파라미터, 함수포인터 (0) | 2024.01.22 |
---|---|
인수 전달 (0) | 2024.01.16 |
vector (0) | 2024.01.16 |
for-each (0) | 2024.01.16 |
enum, 구조체 (0) | 2024.01.16 |
댓글