M.4 std::move


https://www.learncpp.com/cpp-tutorial/stdmove/
moveの意味をもっと頻繁に使うと
l-valueの場合moveの意味を適用できます
#include <iostream>
#include <string>

template<class T>
void myswap(T& a, T& b)
{
  T tmp { a }; // invokes copy constructor
  a = b; // invokes copy assignment
  b = tmp; // invokes copy assignment
}

int main()
{
	std::string x{ "abc" };
	std::string y{ "de" };

	std::cout << "x: " << x << '\n';
	std::cout << "y: " << y << '\n';

	myswap(x, y);

	std::cout << "x: " << x << '\n';
	std::cout << "y: " << y << '\n';

	return 0;
}
上記swapを行う場合
myswap関数は3回コピーされます
前回の授業で知ったように、copyは無効です.
そして例として、本swapは3回のcopyを使用する
これによりstring copyとdestructが多すぎてプログラムが遅くなります
しかし、copyはここでは必要ありません.私たちに必要なのはaとbの値を交換するだけです.そのため、私たちは3回移動するだけでこの目的を達成することができます.しかもこれはcopyを使うときよりも効率的です.
しかし、どのようにしてそれを実現しますか?ここの問題はすべてl-valueです
r-valuerefではなくl-valueなので、move constructorまたはmove付与を呼び出すことはできません.では、どうすればいいのでしょうか.

std::move


c++11にはstd::moveという標準ライブラリ関数があります.
static castを使用してパラメータをr-valuereferenceに変換します
したがってmoveの意味が呼び出されます
したがって、std::move関数を使用して、l-valueを使用することなくmove constructorを呼び出し、値を割り当てることができます.std::moveはユーティリティヘッダで定義されていることに注意してください.
これはstd::moveを使用する同じ例です.
#include <iostream>
#include <string>
#include <utility> // for std::move

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

int main()
{
	std::string x{ "abc" };
	std::string y{ "de" };

	std::cout << "x: " << x << '\n';
	std::cout << "y: " << y << '\n';

	myswap(x, y);

	std::cout << "x: " << x << '\n';
	std::cout << "y: " << y << '\n';

	return 0;
}
前の例とは異なりmywapではmoveの意味が3回呼び出されていることがわかります
copyを作成する前にmoveでより効率的なプログラムになります

Another example


std::moveを使用してstd::vectorのようなコンテナに対してl-valueを使用してmoveの意味を適用することができます.
次の例では、copyの意味とmoveの意味が同時に存在します.
#include <iostream>
#include <string>
#include <utility> // for std::move
#include <vector>

int main()
{
	std::vector<std::string> v;
	std::string str = "Knock";

	std::cout << "Copying str\n";
	v.push_back(str); // calls l-value version of push_back, which copies str into the array element

	std::cout << "str: " << str << '\n';
	std::cout << "vector: " << v[0] << '\n';

	std::cout << "\nMoving str\n";

	v.push_back(std::move(str)); // calls r-value version of push_back, which moves str into the array element

	std::cout << "str: " << str << '\n';
	std::cout << "vector:" << v[0] << ' ' << v[1] << '\n';

	return 0;
}

Where else is std::move useful?


多くのソートアルゴリズムはswapingを使用します
この場合std::moveのmove semanticsを使用するとより効果的です
また、スマートポインタで管理されているコンテンツを移動したい場合にも役立ちます.

Conclusion


std::moveはいつでもr-valueのようにl-valueを扱うことができる
これは通常move semanticsを呼び出すためです