M.3 Move constructors and move assignment


https://www.learncpp.com/cpp-tutorial/move-constructors-and-move-assignment/
第1課M.1ではstd::auto ptrを確認した
ここではmoveの意味の必要性を理解した.
copyの意味で実装する際の欠点も確認した.
このコースでは、c++11でmoveコンストラクション関数とmove割り当てを使用してこれらの問題を解決する方法について説明します.

Move constructors and move assignment


c++11ではmoveの意味に2つの新しい関数が定義されています.
moveコンストラクション関数とmove付与オペレータ
copyコンストラクション関数とcopy付与の目的がobjectのcopyを作成して別のobjectを作成する場合、moveコンストラクション関数とmove付与の目的は所有権の移転です.
moveコンストラクション関数と定義付与値はcopyクラスに似ています
ただし、copyがパラメータをl-valuerefに設定するのとは逆に、
move r-valuerefを使用してパラメータを設定する
ここに例があります
deep copy copy構造関数、付与値、およびの比較
moveコンストラクション関数、割り当て値
#include <iostream>

template<class T>
class Auto_ptr4
{
	T* m_ptr;
public:
	Auto_ptr4(T* ptr = nullptr)
		:m_ptr(ptr)
	{
	}

	~Auto_ptr4()
	{
		delete m_ptr;
	}

	// Copy constructor
	// Do deep copy of a.m_ptr to m_ptr
	Auto_ptr4(const Auto_ptr4& a)
	{
		m_ptr = new T;
		*m_ptr = *a.m_ptr;
	}

	// Move constructor
	// Transfer ownership of a.m_ptr to m_ptr
	Auto_ptr4(Auto_ptr4&& a) noexcept
		: m_ptr(a.m_ptr)
	{
		a.m_ptr = nullptr; // we'll talk more about this line below
	}

	// Copy assignment
	// Do deep copy of a.m_ptr to m_ptr
	Auto_ptr4& operator=(const Auto_ptr4& a)
	{
		// Self-assignment detection
		if (&a == this)
			return *this;

		// Release any resource we're holding
		delete m_ptr;

		// Copy the resource
		m_ptr = new T;
		*m_ptr = *a.m_ptr;

		return *this;
	}

	// Move assignment
	// Transfer ownership of a.m_ptr to m_ptr
	Auto_ptr4& operator=(Auto_ptr4&& a) noexcept
	{
		// Self-assignment detection
		if (&a == this)
			return *this;

		// Release any resource we're holding
		delete m_ptr;

		// Transfer ownership of a.m_ptr to m_ptr
		m_ptr = a.m_ptr;
		a.m_ptr = nullptr; // we'll talk more about this line below

		return *this;
	}

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

class Resource
{
public:
	Resource() { std::cout << "Resource acquired\n"; }
	~Resource() { std::cout << "Resource destroyed\n"; }
};

Auto_ptr4<Resource> generateResource()
{
	Auto_ptr4<Resource> res(new Resource);
	return res; // this return value will invoke the move constructor
}

int main()
{
	Auto_ptr4<Resource> mainres;
	mainres = generateResource(); // this assignment will invoke the move assignment

	return 0;
}
上記のプログラムではgenerateResource()がr-valueを生成することがわかります
したがってmove付与オペレータが呼び出されます
この場合,copy constructorとは異なり,moveの意味を簡単に実現する.
copyを呼び出すと、次のように出力されます.
Resource acquired
Resource acquired
Resource destroyed
Resource acquired
Resource destroyed
Resource destroyed
moveが呼び出されると、出力は次のようになります.
Resource acquired
Resource destroyed

When are the move constructor and move assignment called?


move constructor,assignmentは対応する関数を定義し,r-valueを構造またはassignmentのパラメータで渡すと呼び出す
ほとんどの場合、r-valueはliteralか一時valueかanonymousobjectか
move constructorまたはmove assignmentが定義されていない場合はdefaultは呼び出されません

The key insight behind move semantics


パラメータがl-valueの場合、オブジェクトの構築または割り当て中に
最も合理的な方法はl-valueをコピーしてobjectを生成することです
l-valueの代わりに安全だと正確に答えることはできないからです
後でプログラムで再利用するかもしれません...
ただし、r-valueの場合、r-valueは一時値であるため、moveによる方法が妥当である
どうせ表情から離れると破壊されるからだ.
c++11では、r-valueとl-valueを共有することで、よりスマートで効率的な意思決定が可能になります.
残りの内容は多いですが、ここでは省略…