0

移動セマンティクスをテストしようとして、メモリを割り当てる単純なクラスを構築します。

class CTest
{
    private:
        std::size_t size;
        char* buffer;

    public:
        CTest(std::size_t size) : size(size), buffer(nullptr)
        {
            buffer = new char[size];
        }

        ~CTest()
        {
            delete[] buffer;
        }

        CTest(const CTest& other) : size(other.size), buffer(nullptr)
        {
            buffer = new char[size];
        }

        CTest(CTest&& other) : size(other.size), buffer(other.buffer)
        {
            other.buffer = nullptr;
        }
};

ご覧のとおり、参照によってコピーすると新しいメモリが割り当てられる非常に単純なクラスです(テストのためだけに、その内容をコピーしません)。移動コンストラクターは、引数データを指す内部ポインターを作成するだけで、新しいメモリは割り当てられません。

次のようなヘルパー関数で Windows QueryPerformanceCounter() を使用して im をベンチマークする場合:

template <typename Func>
__int64 Benchmark(Func f, size_t count)
{
    LARGE_INTEGER li = {};
    QueryPerformanceCounter(&li);
    __int64 start = li.QuadPart;

    f(count);

    QueryPerformanceCounter(&li);
    return li.QuadPart - start;
}

非常に単純なベンチマーク関数で、開始時間を保存し、終了時間から減算して結果を返します。テスト機能については次のとおりです。

void Alloc_Ref(size_t count)
{
    CTest t(1024);
    for(size_t i = 0; i < count; ++i)
        CTest c(t);
}

void Alloc_Move(size_t count)
{
    for(size_t i = 0; i < count; ++i)
        CTest c(CTest(1024));
}

Alloc_Ref は事前に初期化された変数を使用するため、コピー コンストラクターを呼び出します。Alloc_Move は単に一時クラスを使用するため、移動コンストラクターを呼び出します。

次のようにテストを呼び出しています:

cout << "Ref: " << Benchmark(Alloc_Ref, 1000000) << " ms." << endl;
cout << "Move: " << Benchmark(Alloc_Move, 1000000) << " ms." << endl;

問題は、Alloc_Move が移動コンストラクターを呼び出しておらず、引き続きコピー コンストラクターを呼び出していることです。不足しているものはありますか?

同様に重要なのは、Alloc_Move でこれを行う場合です。CTest c(move(CTest(1024))移動コンストラクターを呼び出しますが、Alloc_Ref コンストラクターよりも遅いですが、何か不足していますか?

長い投稿で申し訳ありませんが、よろしくお願いします。

4

2 に答える 2

3

問題は、Alloc_Move移動コンストラクターを呼び出しておらず、引き続きコピー コンストラクターを呼び出していることです。不足しているものはありますか?

あなたの分析は正しくありません。Visual C++ 2010 SP1 コンパイラを使用している場合Alloc_Move、コピー コンストラクターも移動コンストラクターも呼び出しません。宣言と初期化

CTest c(CTest(1024));

に変換されます

CTest c(1024);

つまりc、コンストラクターを呼び出すことによって直接初期化されCTest(std::size_t size)ます。一時CTestオブジェクトは作成または破棄されません。


Alloc_Move私の Visual Studio 2010 32 ビット VM では、関数と関数のパフォーマンスに約 20% の違いがあることがわかりますAlloc_Ref(後者の方が高速です)。生成されたアセンブリをざっと見ましたが、違いの明らかな原因はわかりませんでした。Visual C++ 11 Beta コンパイラ (x86 用) をAlloc_Move使用すると、2 倍以上高速になりますAlloc_Ref(これ以上調査していないため、理由はわかりません)。

[測定単位が間違っていることにも注意してください QueryPerformanceCounter。ミリ秒を返しません。ティックを返します。QueryPerformanceFrequency呼び出して 1 秒あたりのティック数を取得し、それに応じて測定値を分割する必要があります。]

于 2012-04-16T20:42:37.423 に答える
-2

移動セマンティクスを利用するには、右辺値参照を明示的に使用する必要があります。古いコードとの互換性のために、コンパイラが右辺値参照に暗黙的にキャストすることはありません。std::move使用するか、明示的にキャストする必要があります。

を構築するたびAlloc_Moveに新しいを構築しているため、おそらく遅くなります。asは単一の構築と再利用のみを行います。CTest(1024)cAlloc_RefCTest(1024)

于 2012-04-16T19:30:25.893 に答える