ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • C++ Study. move assignment operator
    c++ 2024. 1. 21. 16:52

    move semantics

    • 기존의 복사 대입 연산자(copy assignment operator)와는 다르게 이동 대입 연산자(move assignment operator)를 이용하여 객체 소유권을 이전하여 메모리를 효율적으로 이동시키는 것

     

    move semantics을 하기 위해 필요한 것들

    1. std::move() 함수
      • 복사 대입 연산자가 아닌 이동 대입 연산자를 호출하기 위해 사용
      • 단순히, 전달받은 인자를 rvalue reference(참조자)로 캐스팅해서 리턴
        • rvalue reference로 캐스팅하려면 → 타입&&
      static_cast<Object&&>(obj) == std::move(obj1) // 양쪽이 같은 작업 수행
      
    2. move assignment operator(이동 대입 연산자)
      • 우항에 rvalue 참조자가 있고, = 연산이 수행되어야 할 때 호출되는 연산자
      • 클래스 만들 때 이걸 정의해줘야 이동 연산이 된다. 없으면 복사 대입 연산자가 수행됨.
      • 클래스에서 연산자 오버라이딩하듯이 정의내리면 된다.

    예시 코드

    #include <iostream>
    
    class MyString {
    private:
    	char* data;
    
    public:
    	// 생성자, 소멸자, 복사 생성자 등 생략
    	
    	// 이동 대입 연산자 정의
    	MyString& operator=(MyString&& other) noexcept {
    		if (this != &other) {
    			delete[] data; // 기존 데이터 삭제 
    			data = other.data; // other의 데이터를 기존 data로 이동(data 포인터가 가리키는 주소 변경)
    			other.data = nullptr; // other의 데이터는 nullptr을 가리키도록 함
    		}
    		return *this; // 해당 객체의 lvalue 반환
    	}
    };
    
    int main() {
    	MyString str1("Hello");
    	MyString str2("World");
    
    	// 이동 함수(move) 호출 -> 내부적으로 이동 대입 연산자가 호출됨
    	str1 = std::move(str2);
    	
    	return 0;
    

     

    &&에 대한 설명

    • rvalue 참조를 한다.
    • &&와 &의 다른점?
    • 예시코드
    int a = 10;
    
    int &b = a; // OK. a는 lvalue.
    int &&c = a; // Compile Error: a는 lvalue인데 &&는 rvalue 참조 
    int &&c = 10; // OK, 10은 리터럴로 rvalue
    
    • b는 lvalue 참조자이다. lvalue는 객체를 수정하거나 다른 함수로 전달할 때 유용
    • c는 rvalue 참조자이다. 오른쪽 값(임시 객체, 리터럴 등)을 참조하기 위해 사용.
    • &는 lvalue 참조이다.

     

    • 왜 rvalue 참조가 필요한지?
    • -> rvalue 참조는 주로 move semantic에서 활용된다. move는 복사가 아니라 rvalue값 자체가 이동되어야 하고, 임시 객체나 rvalue는 그 자체로 이동이 가능한 값이기 때문에 rvalue 참조를 통해 rvalue에 접근해서 이동 연산을 수행한다.

     

    • lvalue 참조(&)로 move assignment operator 구현하면 어떻게 되나?
    MyClass& operator=(const MyClass& other) {
    		// data = &other->data;
    		// other->data = null; // error
    
        // 잘못된 방식: Lvalue 참조를 사용하여 복사 연산을 수행
        // 이 경우 이동 의미론의 이점을 활용할 수 없음
        // 새로운 객체에 복사를 수행하는 것으로, 이는 기존 복사 대입 연산자와 다르지 않음
        // 실제로 소유권의 이동이 아닌, 단순한 복사가 이루어짐
        // ...
        return *this;
    }
    

     

    • 임시 객체란(Temporary Object)?
    • -> 임시객체란 표현식이 평가되면서 생성되고, 해당 표현식이 종료되면 자동으로 소멸되는 임시적인 객체를 말한다. 함수 호출, 연산 등에서 자주 발생한다.
    // 1. 함수 호출시
    int add(int a, int b) {
    	return a + b;
    }
    
    int result = add(3, 4); // 임시 객체가 반환됨, int는 이동 대입 연산자 없어서 복사 일어남 
    
    // 2. 연산
    string fullName = "John" + " " + "Doe"; // 문자열 연결 시 임시 객체 생성, 이동 일어남
    
    // 3. 형변환
    double value = 3.14;
    int intValue = static_cast<int>(value); // static_cast 시에 임시 객체 생성됨
    
    // 4. 임시 객체를 반환하는 함수
    string getName() {
    	return "Alice"; // 임시 객체 반환
    }
    
    int temp(){
    	string name = getName(); // getName()의 반환값이 임시객체,
    	// 반환값은 문자열 리터럴이라 lvalue지만 임시객체이기 때문에 move semantic이 일어남.
    }
    

     

    참고

    https://kukuta.tistory.com/426

    'c++' 카테고리의 다른 글

    C++ Study. module system  (0) 2024.01.21
    C++ Study. stl unordered_set  (0) 2024.01.21
    C++ Study. final, override  (1) 2024.01.21
    C++ 스터디. standard template library  (1) 2024.01.21
    C++ Primer CH15. Object-Oriented Programming  (0) 2024.01.21
Designed by Tistory.