AutoPtr.h

#include <iostream>
using namespace std;

template<typename T>
class AutoPtr
{
public:
	T* m_ptr;

public:
	AutoPtr(T* ptr = nullptr)
		:m_ptr(ptr) 
	{
		cout << "AutoPtr default constructor" << endl;
	}

	~AutoPtr()
	{
		cout << "AutoPtr destructor" << endl;

		if (m_ptr != nullptr) delete m_ptr;
	}

	AutoPtr(const AutoPtr& a) // ๐Ÿ’Ž๋ณต์‚ฌ ์ƒ์„ฑ์ž๐Ÿ’Ž 
	{
		cout << "AutoPtr copy constructor" << endl;

		// deep copy
		m_ptr = new T;  
		*m_ptr = *a.m_ptr; // ๐Ÿ“œResource.h ์˜ ๋Œ€์ž… ์—ฐ์‚ฐ์ž ํ˜ธ์ถœํ•˜์—ฌ ๊นŠ์€ ๋ณต์‚ฌ ์ˆ˜ํ–‰
			
	}

	AutoPtr& operator = (const AutoPtr& a) // ๐Ÿ’Ž๋Œ€์ž… ์—ฐ์‚ฐ์ž ์˜ค๋ฒ„๋กœ๋”ฉ๐Ÿ’Ž
	{
		cout << "AutoPtr copy assignment" << endl;
		
		if (&a == this)
			return *this;

		if (m_ptr != nullptr) delete m_ptr;

		// deep copy
		m_ptr = new T;  
		*m_ptr = *a.m_ptr; // ๐Ÿ“œResource.h ์˜ ๋Œ€์ž… ์—ฐ์‚ฐ์ž ํ˜ธ์ถœํ•˜์—ฌ ๊นŠ์€ ๋ณต์‚ฌ ์ˆ˜ํ–‰
														
		return *this;
	}
	//AutoPtr(const AutoPtr& a) = delete;
	//AutoPtr& operator = (**const** AutoPtr& a) = delete;  

	AutoPtr(AutoPtr&& a)  // ๐Ÿ’Ž์ด๋™์ƒ์„ฑ์ž๐Ÿ’Ž
		:  m_ptr(a.m_ptr) // ์†Œ์œ ๊ถŒ ์ด์ „
	{ 
		a.m_ptr = nullptr; // ์†Œ์œ ๊ถŒ ๋ฐ•ํƒˆ
	
		cout << "AutoPtr move constructor" << endl;
	}

	AutoPtr& operator = (AutoPtr&& a)  // ๐Ÿ’Ž์ด๋™ ๋Œ€์ž… ์—ฐ์‚ฐ์ž ์˜ค๋ฒ„๋กœ๋”ฉ๐Ÿ’Ž 
	{
		cout << "AutoPtr move assignment" << endl;

		if (&a == this)
			return *this;

		if (m_ptr != nullptr) delete m_ptr; 
		
		m_ptr = a.m_ptr;  // ์†Œ์œ ๊ถŒ ์ด์ „
		a.m_ptr = nullptr;  // ์†Œ์œ ๊ถŒ ๋ฐ•ํƒˆ

		return *this;
	}

	T& operator *() const { return *m_ptr; }
	T& operator ->() const { return m_ptr; }
	bool inNull() const { return m_ptr == nullptr; }
};

main.cpp

#include <iostream>

int main()
{
	{
		AutoPtr<Resource> res1(new Resource(10000000));

		cout << res1.m_ptr << endl;

		AutoPtr<Resource> res2 = res1; //  ๋ณต์‚ฌ ์ƒ์„ฑ์ž๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค. res1์€ L-Value๋‹ˆ๊นŒ 
        //move semantics๋กœ ๋ฐ”๊พธ๊ณ  ์‹ถ๋‹คํ•˜๋ฉด AutoPtr<Resource> res2 = std::move(res1); //L-value๋ฅผ R-value๋กœ ๋ฐ”๊ฟ”์ค€๋‹ค.

		cout << res1.m_ptr << endl;
		cout << res2.m_ptr << endl;
        
	}
    
    return 0;
}

์ถœ๋ ฅ

Resource length constructed
AutoPtr default constructor
0033F510
AutoPtr copy constructor
Resource default constructed
Resource copy assignment
0033F510
0033F5F0 // => ์ฃผ์†Œ๊ฐ€ ๋‹ค๋ฅด๋‹ค // copy semantics
AutoPtr destructor
Resource destroyed
AutoPtr destructor
Resource destroyed

์ถœ๋ ฅ

Resource length constructed
AutoPtr default constructor
001FF540
AutoPtr move constructor
00000000
001FF540
AutoPtr destructor
Resource destroyed
AutoPtr destructor

๋‹ค๋ฅธ ์˜ˆ์ œ

#include <iostream>

using namespace std;

template<class T>
void MySwap(T &a, T &b)
{
    //T tmp = a;
    //a = b;
    //b = tmp;
    
    T tmp{ std::move(a) };
    a = std::move(b);
    b = std::move(tmp);
}

int main()
{
    {
        AutoPtr<Resource res1(new Resource(3));
        res1->setAll(3);
        
        AutoPtr<Resource> res2(new Resource(5));
        res2->setAll(5);
        
        MySwap(res1, res2);
        
        res1->print();
        res2->print();
    }
    return 0;
}

Resource.h

#include <iostream>
using namespace std;

class Resource
{
public:
	int * m_data = nullptr;
	unsigned m_length = 0;

public:
	Resource() // ๊ธฐ๋ณธ ์ƒ์„ฑ์ž
	{
		cout << "Resource constructed" << endl;
	}

	Resource(unsigned length) // ์ผ๋ฐ˜ ๋งค๊ฐœ๋ณ€์ˆ˜ 1๊ฐœ ์ƒ์„ฑ์ž
	{
		cout << "Resource length constructed" << endl;
		this->m_data = new int[length];
		this->m_length = length;
	}

	Resource(const Resource &res) // ๐Ÿ’Ž๋ณต์‚ฌ ์ƒ์„ฑ์ž๐Ÿ’Ž 
	{
		cout << "Resource copy constructed" << endl;
		
		Resource(res.m_length);

		for (unsigned i = 0; i < m_length; ++i)  // ๋‚ด์šฉ๋ฌผ์„ ์ „๋ถ€ ๊นŠ์€ ๋ณต์‚ฌ (์‹œ๊ฐ„์ด ๊ฝค ๊ฑธ๋ฆผ)
			m_data[i] = res.m_data[i];
	}
 
	~Resource()  // ์†Œ๋ฉธ์ž
	{
		cout << "Resource destroyed" << endl;
	}

	Resource & operator = (Resource & res)  // ๐Ÿ’Ž๋Œ€์ž… ์—ฐ์‚ฐ์ž ์˜ค๋ฒ„๋กœ๋”ฉ๐Ÿ’Ž
	{
		cout << "Resource copy assignment" << endl;

		if (&res == this) return *this; // ๋Œ€์ž…ํ•˜๋ ค๋Š”๊ฒŒ ์ž๊ธฐ ์ž์‹ ์ด๋ฉด ์•„๋ฌด๊ฒƒ๋„ ์•ˆํ•จ
		
		if (this->m_data != nullptr) delete[] m_data; // 1. ๋‚ด ์ž์‹ ์˜ m_data ๋น„์›Œ์ฃผ๊ธฐ

		m_length = res.m_length; // 2. ๋Œ€์ž…์œผ๋กœ ๋„˜๊ฒจ๋ฐ›์€ res์˜ length ๋กœ ๋‚ด length ๊ฐฑ์‹ 
		
		m_data = new int[m_length]; // 3. ๋น„์›Œ์ง„ ๋‚ด ์ž์‹ ์˜ m_data์— ์ƒˆ๋กœ์šด ๊ณต๊ฐ„ ํ• ๋‹น๋ฐ›๊ธฐ
		for (unsigned i = 0; i < m_length; ++i) // 4. m_data๋‚ด์šฉ๋ฌผ ๋„ฃ๊ธฐ.
			m_data[i] = res.m_data[i]; //  ๋Œ€์ž…์œผ๋กœ ๋„˜๊ฒจ๋ฐ›์€ res์˜ m_data ๋‚ด์šฉ๋ฌผ๋“ค์„ **๋‚ด m_data**์— ๊นŠ์€ ๋ณต์‚ฌ

		return *this;
	}
    
    void print()
    {
        for(unsigned i=0;i<m_length;++i)
            std::cout << m_data[i] << " ";
       std::cout << "\n";
    }
    
    void setAll(const int& v)
    {
        for (unsigned i=0;i<m_length;++i)
        {
            m_data[i] = v;
        }
    }
};

๋‹ค๋ฅธ ์˜ˆ์ œ

#include <iostream>
#include <utility> // โœจโœจ
#include <vector>

int main()
{
	{
		vector<string> v;
		string str = "Hello";

		v.push_back(str); //copy semantics

		cout << str << endl; // Hello ๊ทธ๋Œ€๋กœ ์žˆ๋‹ค.
		cout << v[0] << endl;

		v.push_back(std::move(str)); // move semantics

		cout << str << endl;
		cout << v[0] << " " << v[1] << endl;
	}
	
	return 0;
}

์ถœ๋ ฅ

Hello
Hello
                  ๐Ÿ‘ˆ null ์ด์–ด์„œ ๋น„์›Œ์ง„ ๋ถ€๋ถ„
Hello Hello