codenuri 강석민 강사 강의 내용기반으로 정리한 내용입니다.
using move
#include <iostream>
class Test
{
public:
    Test() {}
    ~Test() {}
    Test(const Test& t) { cout << "Copy" << endl; }
    Test(Test&& t) { cout << "Move" << endl; }
    Test& operator=(const Test& t) { 
        cout << "Copy=" << endl;
        return *this; 
    } // 복사 대입연산자
    Test& operator=(Test&& t) { 
        cout << "Move=" << endl;
        return *this; 
    } // move 대입연산자
};
template<typename T> void Swap(T& x, T& y)
{
    Test temp = x; // 복사 생성자
    x = y; // 복사 대입
    y = temp;
}
int main()
{
    Test t1, t2;
    Swap(t1, t2);
}
Copy Copy= Copy= 순으로 출력됨
Swap을 복사 없이 이동만으로 만들기
move 와 swap
#include <iostream>
#include <algorithm>
class Test
{
public:
    Test() {}
    ~Test() {}
    Test(const Test& t) { cout << "Copy" << endl; }
    Test(Test&& t) { cout << "Move" << endl; }
    Test& operator=(const Test& t) { 
        cout << "Copy=" << endl;
        return *this; 
    } // 복사 대입연산자
    Test& operator=(Test&& t) { 
        cout << "Move=" << endl;
        return *this; 
    } // move 대입연산자
};
template<typename T> void Swap(T& x, T& y)
{
    Test temp = move(x);
    x = move(y);
    y = move(temp);
}
int main()
{
    Test t1, t2;
    // Swap(t1, t2);
    swap(t1, t2);
}
Move Move= Move= 순으로 출력됨
이미 STL의 Swap은 move 로 구현되어 있음
만일 move 를 안만들었다면 복사생성자가 불림
move 와 버퍼 복사
#include <iostream>
#include <vector>
#include <algorithm>
class Test
{
public:
    Test() {}
    ~Test() {}
    Test(const Test& t) { cout << "Copy" << endl; }
    // Test(Test&& t) { cout << "Move" << endl; }
    Test(Test&& t) noexcept { cout << "Move" << endl; }
    Test& operator=(const Test& t) { 
        cout << "Copy=" << endl;
        return *this; 
    } // 복사 대입연산자
    // Test& operator=(Test&& t) { 
    Test& operator=(Test&& t) noexcept { 
        cout << "Move=" << endl;
        return *this; 
    } // move 대입연산자
};
template<typename T> void Swap(T& x, T& y)
{
    Test temp = move(x);
    x = move(y);
    y = move(temp);
}
int main()
{
    Test* p1 = new Test[2];
    Test* p2 = new Test[4];
    for(int i = 0; i < 2; i++)
        // p2[i] = p1[i]; // copy 대입
        p2[i] = move(p1[i]); // move 대입
    vector<Test> v(2);
    v.resize(4);
}
작은 버퍼에서 큰 버퍼로 옮길 때 move 생성자를 쓰는 것이 성능 효과적
STL의 vector 가 move 로 되어 있음
noexcept 를 붙여야 Move 이며 Move 대입이 아니라 Move 생성을 사용함
move & noexcept
STL이 어떻게 복사를 하고 있는지
#include <iostream>
#include <vector>
#include <algorithm>
#include <type_traits>
class Test
{
public:
    Test() { cout << "Test()" << endl; }
    ~Test() { cout << "~Test()" << endl; }
    Test(const Test& t) { cout << "Copy" << endl; }
    Test(Test&& t) noexcept { cout << "Move" << endl; }
    Test& operator=(const Test& t) { 
        cout << "Copy=" << endl;
        return *this; 
    }
    Test& operator=(Test&& t) noexcept { 
        cout << "Move=" << endl;
        return *this; 
    }
};
template<typename T> void Swap(T& x, T& y)
{
    Test temp = move(x);
    x = move(y);
    y = move(temp);
}
int main()
{
    /*
    Test* p1 = new Test[2];
    Test* p2 = new Test[4];
    for(int i = 0; i < 2; i++)
        p2[i] = move(p1[i]); // move 대입
    */
    Test t1;
    Test t2 = t1; // copy
    Test t3 = move(t2); // move
    bool b = is_nothrow_move_constructible<Test>::value; // move 실패 여부를 조사할 수 있는 traits(예외 있으면 true)
    cout << b << endl;
    Test t4 = move_if_noexcept(t1); // t1의 move 생성자의 예외가 없으면 move로 있으면 copy로 옮김
}
move 생성자의 예외가 없을 때만 move를 하는 것이 안전한 코드이고 이를 위해 noexcept 키워드를 적어주어야함
move를 활용한 버퍼 복사
#include <iostream>
#include <vector>
#include <algorithm>
#include <type_traits>
using namespace std;
class Test
{
public:
    Test() { cout << "Test()" << endl; }
    ~Test() { cout << "~Test()" << endl; }
    Test(const Test& t) { cout << "Copy" << endl; }
    Test(Test&& t) noexcept { cout << "Move" << endl; }
    Test& operator=(const Test& t) { 
        cout << "Copy=" << endl;
        return *this; 
    }
    Test& operator=(Test&& t) noexcept { 
        cout << "Move=" << endl;
        return *this; 
    }
};
int main()
{
    Test* p1 = new Test[2];
    // Test* p2 = new Test[4];
    // 1. 신규 버퍼는 메모리만 할당 한다.
    Test* p2 = static_cast<Test*>(operator new(sizeof(Test)*4));
    for(int i = 0; i < 2; i++)
    {
        // p2[i] = move(p1[i]);
        // new(&p2[i]) Test; // 디폴트 생성자 호출
        // new(&p2[i]) Test(p1[i]); // 복사 생성자
        // new(&p2[i]) Test(move(p1[i])); // move 생성자
        new(&p2[i]) Test(move_if_noexcept(p1[i]));
    }
    // 2. 새로운 객체는 디폴트 생성자 호출
    for(int i = 2; i < 4; i++)
    {
        new(&p2[i]) Test; // 디폴트 생성자 호출.
    }
}
#include <iostream>
#include <vector>
#include <algorithm>
#include <type_traits>
using namespace std;
class Test
{
public:
    Test() { cout << "Test()" << endl; }
    ~Test() { cout << "~Test()" << endl; }
    Test(const Test& t) { cout << "Copy" << endl; }
    Test(Test&& t) noexcept { cout << "Move" << endl; }
    Test& operator=(const Test& t) { 
        cout << "Copy=" << endl;
        return *this; 
    }
    Test& operator=(Test&& t) noexcept { 
        cout << "Move=" << endl;
        return *this; 
    }
};
int main()
{
    Test* p1 = static_cast<Test*>(operator new(sizeof(Test)*2));
    for(int i = 0; i < 2; i++)
    {
        new(&p1[i]) Test;
    }
    Test* p2 = static_cast<Test*>(operator new(sizeof(Test)*4));
    for(int i = 0; i < 2; i++)
    {
        new(&p2[i]) Test(move_if_noexcept(p1[i]));
    }
    for(int i = 2; i < 4; i++)
    {
        new(&p2[i]) Test;
    }
    // 최초 버퍼 파괴
    for(int i = 1; i >= 0; i--)
    {
        p1[i].~Test();
    }
    operator delete(p1);
    cout << "--" << endl;
    // 신규 버퍼 파괴
    for(int i = 3; i >= 0; i--)
    {
        p2[i].~Test();
    }
    operator delete(p2);
}
#include <iostream>
#include <vector>
using namespace std;
class Test
{
public:
    Test() { cout << "Test()" << endl; }
    ~Test() { cout << "~Test()" << endl; }
    Test(const Test& t) { cout << "Copy" << endl; }
    Test(Test&& t) noexcept { cout << "Move" << endl; }
    Test& operator=(const Test& t) { 
        cout << "Copy=" << endl;
        return *this; 
    }
    Test& operator=(Test&& t) noexcept { 
        cout << "Move=" << endl;
        return *this; 
    }
};
int main()
{
    vector<Test> v(2);
    v.resize(4);
    cout << "--" << endl;
}