38

重複の可能性:
移動セマンティクス==カスタムスワップ関数は廃止されましたか?

これはstd::swapC++11でどのように見えるかです:

template<typename T>
void swap(T& x, T& y)
{
  T z = std::move(x);
    x = std::move(y);
    y = std::move(z);
}

もちろん、私のクラスがムーブコンストラクターとムーブ代入演算子を定義している場合、私はまだstd::swap自分の型に特化する必要がありますか、それともそれが得られるのと同じくらい効率的ですか?std::swap

4

4 に答える 4

36

の特殊化std::swapはオプションになりましたが、非推奨ではありません。理由はパフォーマンスです。

コードのプロトタイピングの場合、そしておそらく多くの出荷コードの場合でも、std::swap十分に高速です。ただし、コードを少しずつ調べなければならない状況にある場合でも、カスタム スワップを作成すると、パフォーマンスが大幅に向上する可能性があります。

クラスが本質的に 1 つの所有ポインターを持ち、ムーブ コンストラクターとムーブ代入がその 1 つのポインターを処理する必要がある場合を考えてみましょう。各メンバーのマシンのロードとストアをカウントします。

コンストラクターの移動: 1 つのロードと 2 つのストア。

移動の割り当て: 2 つのロードと 2 つのストア。

カスタム スワップ: 2 つのロードと 2 つのストア。

std::swap1 回の建設と 2 回の移動割り当て、または 5 回のロードと 6 回のストアです。

カスタム スワップは、潜在的に .NET よりも 2 倍または 3 倍高速ですstd::swap。ロードとストアをカウントして何かの速度を把握しようとするときはいつでも、どちらも非常に高速になります。

std::swap注: 移動割り当てのコストを計算する際には、(アルゴリズムで) 移動元の値に移動することを考慮してください。これにより、多くの場合、ブランチのコストがかかりますが、解放のコストがなくなります。

于 2011-12-23T15:04:55.067 に答える
4

std::swap移動のセマンティクスがあるため、特殊化は非推奨ですか?

いいえ。これは一般的なバージョンですが、3 回目の移動操作をスキップするように最適化できます。私の好みは、コピーアンドスワップのstd::swapイディオムとクラスのカスタマイズを組み合わせることです。

つまり、次のようになります。

class Aaaa
{
public:
    Aaaa(); // not interesting; defined elsewhere
    Aaaa(Aaaa&& rvalueRef); // same
    Aaaa(const Aaaa& ref); // same
    ~Aaaa(); // same
    Aaaa& operator=(Aaaa object) // copy&swap
    {
        swap(object);
        return *this;
    }
    void swap(Aaaa& other)
    {
        std::swap(dataMember1, other.dataMember1);
        std::swap(dataMember2, other.dataMember2);
        // ...
    }

    // ...
};

namespace std
{
    template<> inline void std::swap(Aaaa& left, Aaaa& right)
    { left.swap(right); }
}
于 2011-12-23T15:01:05.653 に答える
0

それはあなたのタイプに依存します。

x から z、y から x、z から y に移動します。これは、基礎となる表現の 3 つのコピー操作です (おそらく 1 つのポインターのみ、またはそれ以上の何かがわかります)。

これで、タイプのより高速なスワップを作成できる可能性があります (xor スワップ トリック、インライン アセンブラー、または基礎となるタイプの std::swap の方が高速です)。

または、コンパイラが最適化に優れており、本質的に両方のケースを同じ命令に最適化します (レジスタに一時的なものがあるように)。

個人的には、移動代入や YMMV など、いくつかの場所から呼び出されるスワップ メンバー関数を常に実装する傾向があります。

于 2011-12-23T14:48:37.243 に答える
0

これswap()は、移動コンストラクターと 2 つの移動代入を呼び出します。swap()彼の特定のタイプのクラスについては、より効率的に書くことができると思います。

class X
{
    int * ptr_to_huge_array;
public:
// ctors, assgn ops. etc. etc.

    friend void swap(X& a, X& b)
    {
        using std::swap;
        swap(a.ptr_to_huge_array, b.ptr_to_huge_array);
    }
};

移動コンストラクターと代入演算子の実装に関係なく。

于 2011-12-23T14:49:34.300 に答える