C++ 関数の戻り値のコンストラクタ呼び出しとRVO（Visual Studio 2019 Community 16.7.0 Preview 2.0）

Visual Studio 2019 Community Version 16.7.0 Preview 2.0で関数の戻り値のコンストラクタ呼び出しとRVOを確認した結果です。C++言語標準はstd:c++latest（C++20 draft）です。

関数の戻り値となるクラスのコンストラクタの優先順位は「ムーブコンストラクタ→コピーコンストラクタ→通常のコンストラクタ」であることが確認できました。コードの複雑さにもよるかもしれませんが、関数をそのまま返してもRVOやムーブコンストラクタが選択されているので`std::move`は省略できるかもしれません。主にポインタの書き換えなので対した処理ではないですが。

| 方法                                     | Debug構成            | Release構成          |
| ---------------------------------------- | -------------------- | -------------------- |
| コンストラクタをそのまま返す。           | RVO                  | RVO                  |
| 関数内のローカル変数をそのまま返す。     | ムーブコンストラクタ | NRVO                 |
| 関数内のローカル変数をstd:moveして返す。 | ムーブコンストラクタ | ムーブコンストラクタ |
| 別の関数の戻り値をそのまま返す。         | RVO                  | RVO                  |
| 別の関数の戻り値をstd:moveして返す。     | ムーブコンストラクタ | ムーブコンストラクタ |

用語
・RVO：Return Value Optimization
・NRVO：Named Return Value Optimization

## テストコード
```cpp
#include <string>
#include <iostream>

using namespace std;

class TestClass
{
private:
	static int counter;
	int index;

public:
	wstring value;

	// デフォルトコンストラクタ
	TestClass()
		: value(L"<default>"), index(counter++)
	{
		wcout << L"TestClass() : " << index << endl;
	}

	TestClass(wstring_view sv)
		: value(sv), index(counter++)
	{
		wcout << L"TestClass(wstring_view sv) : " << index << endl;
	}

	// コピーコンストラクタ
	TestClass(const TestClass& source)
		: value(source.value), index(counter++)
	{
		wcout << L"TestClass(const TestClass& source) : " << index << endl;
	}

	// ムーブコンストラクタ
	TestClass(TestClass&& source)
		: value(move(source.value)), index(counter++)
	{
		wcout << L"TestClass(TestClass&& source) : " << index << endl;
	}

	~TestClass()
	{
		wcout << L"~TestClass() : " << index << endl;
	}
};

int TestClass::counter = 0;

TestClass f1()
{
	return TestClass(L"abc");
}

TestClass f2()
{
	TestClass tc = TestClass(L"abc");
	return tc;
}

TestClass f3()
{
	TestClass tc = TestClass(L"abc");
	return move(tc);
}

TestClass f4()
{
	return f1();
}

TestClass f5()
{
	return move(f1());
}

int main()
{
	// コンストラクタをそのまま返す。
	{
		auto tc1 = f1();
		wcout << tc1.value << endl;
	}
	wcout << endl;

	// 関数内のローカル変数をそのまま帰す。
	{
		auto tc2 = f2();
		wcout << tc2.value << endl;
	}
	wcout << endl;

	// 関数内のローカル変数をstd:moveして帰す。
	{
		auto tc3 = f3();
		wcout << tc3.value << endl;
	}
	wcout << endl;

	// 別の関数の戻り値をそのまま返す。
	{
		auto tc4 = f4();
		wcout << tc4.value << endl;
	}
	wcout << endl;

	// 別の関数の戻り値をstd:moveして返す。
	{
		auto tc5 = f5();
		wcout << tc5.value << endl;
	}

	return 0;
}

```

```plain:Debug構成の出力
TestClass(wstring_view sv) : 0
abc
~TestClass() : 0

TestClass(wstring_view sv) : 1
TestClass(TestClass&& source) : 2
~TestClass() : 1
abc
~TestClass() : 2

TestClass(wstring_view sv) : 3
TestClass(TestClass&& source) : 4
~TestClass() : 3
abc
~TestClass() : 4

TestClass(wstring_view sv) : 5
abc
~TestClass() : 5

TestClass(wstring_view sv) : 6
TestClass(TestClass&& source) : 7
~TestClass() : 6
abc
~TestClass() : 7
```

```plain:Release構成の出力
TestClass(wstring_view sv) : 0
abc
~TestClass() : 0

TestClass(wstring_view sv) : 1
abc
~TestClass() : 1

TestClass(wstring_view sv) : 2
TestClass(TestClass&& source) : 3
~TestClass() : 2
abc
~TestClass() : 3

TestClass(wstring_view sv) : 4
abc
~TestClass() : 4

TestClass(wstring_view sv) : 5
TestClass(TestClass&& source) : 6
~TestClass() : 5
abc
~TestClass() : 6
```