16

検討:

#include <cstdlib>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;

class Gizmo
{
public:
    Gizmo() : foo_(shared_ptr<string>(new string("bar"))) {};
    Gizmo(Gizmo&& rhs); // Implemented Below

private:
    shared_ptr<string> foo_;
};

/*
// doesn't use std::move
Gizmo::Gizmo(Gizmo&& rhs)
:   foo_(rhs.foo_)
{
}
*/


// Does use std::move
Gizmo::Gizmo(Gizmo&& rhs)
:   foo_(std::move(rhs.foo_))
{
}

int main()
{
    typedef vector<Gizmo> Gizmos;
    Gizmos gizmos;
    generate_n(back_inserter(gizmos), 10000, []() -> Gizmo
    {
        Gizmo ret;
        return ret;
    });

    random_shuffle(gizmos.begin(), gizmos.end());

}

上記のコードには、2つのバージョンがあります。1Gizmo::Gizmo(Gizmo&&)つはstd::move実際にを移動するために使用しshared_ptr、もう1つは単にをコピーするために使用しshared_ptrます。

どちらのバージョンも表面的には機能しているようです。1つの違い(私が見ることができる唯一の違い)は、非moveバージョンでは、の参照カウントshared_ptrが一時的に増加しますが、ほんの短時間です。

私は通常先に進みますmoveshared_ptr、コードで明確で一貫性を保つためだけです。ここで考慮事項がありませんか?技術的な理由で、一方のバージョンをもう一方のバージョンよりも優先する必要がありますか?

4

3 に答える 3

19

ここでの主な問題は、の余分なアトミックインクリメントとデクリメントによる小さなパフォーマンスの違いではなくshared_ptr、移動を実行しない限り、操作のセマンティクスに一貫性がないことです。

shared_ptrの参照カウントは一時的なものであると想定されていますが、その言語ではそのような保証はありません。移動元のソースオブジェクトは一時的なものである可能性がありますが、存続期間がはるかに長くなる可能性もあります。これは、右辺値参照(たとえばstd::move(var))にキャストされた名前付き変数である可能性があります。その場合、移動しないことで、移動元との共有shared_ptr所有権を維持し、移動先のスコープが小さい場合は、尖ったオブジェクトの寿命は不必要に延長されます。shared_ptr

于 2012-06-08T17:47:57.110 に答える
15

私はジェームズ・マクネリスの答えに賛成した。彼の答えについてコメントしたいのですが、私のコメントはコメント形式に収まりません。だから私はそれをここに置いています。

移動とコピーのパフォーマンスへの影響を測定する楽しい方法は、それらの束全体を移動またはコピーして時間を計るshared_ptrようなものを使用することです。vector<shared_ptr<T>>ほとんどのコンパイラには、言語モード(-std = c++03または-std=c ++ 11など)を指定することにより、移動セマンティクスをオン/オフにする方法があります。

これが私が-O3でテストしたばかりのコードです:

#include <chrono>
#include <memory>
#include <vector>
#include <iostream>

int main()
{
    std::vector<std::shared_ptr<int> > v(10000, std::shared_ptr<int>(new int(3)));
    typedef std::chrono::high_resolution_clock Clock;
    typedef Clock::time_point time_point;
    typedef std::chrono::duration<double, std::micro> us;
    time_point t0 = Clock::now();
    v.erase(v.begin());
    time_point t1 = Clock::now();
    std::cout << us(t1-t0).count() << "\u00B5s\n";
}

clang /libc++を使用して-std=c ++ 03で、これは私のために出力されます:

195.368µs

-std = c ++ 11に切り替えると、次のようになります。

16.422µs

あなたのマイレージは異なる場合があります。

于 2012-06-08T18:12:43.903 に答える
13

の使用moveが望ましいです。参照カウントの余分なアトミックインクリメントとデクリメントを必要としないため、コピーよりも効率的である必要があります。

于 2012-06-08T17:26:34.060 に答える