2011-12-23 2 views
32

可能性の重複:
Move semantics == custom swap function obsolete?移動セマンティクスが導入されたので、std :: swapを非推奨にしましたか?

これはstd::swapはC++ 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は、私のクラスが定義している限り、効率的になるでしょうもちろん、代入演算子と移動代入演算子はありますか?

+0

これはScottやHerbが_C++とBeyond_で言いましたが、私はそれについて何も見つけられないようです。 –

+2

関連:[セマンティクスを移動する==カスタムスワップ関数は廃止?](http://stackoverflow.com/questions/6416385/move-semantics-custom-swap-function-obsolete) – Xeo

+0

@Xeo:ありがとう、私は完全に忘れていたその質問/回答。私は一貫性のある点を得るのですか? :-)私はそうでなければ赤面になっていただろう! –

答えて

30

std::swapの専門は今任意ですが、非推奨ではない:私は持っていることを意味します

。その根拠はパフォーマンスです。

プロトタイプコードでは、おそらく多くの出荷コードでも、std::swapは十分速くなります。しかし、あなたのコードから少々控えめにしなければならない状況にあるなら、カスタムスワップを書くことは依然として大きなパフォーマンス上の利点になります。

あなたのクラスに本質的に1つの所有ポインタがあり、あなたの移動コンストラクタと移動割り当てがその1つのポインタを処理する必要がある場合を考えてみましょう。

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

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

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

std::swapは、1移動構成と2移動割り当て、または5負荷と6ストアです。

カスタムスワップは、おそらくstd::swapよりも2〜3倍高速です。ロードとストアを数えることで何かの速度を把握しようとしているときは、どちらも速く邪悪になるでしょう。

注:移動割り当てのコストを計算する際には、必ず移動先の値(std::swapアルゴリズム)に移動することを考慮してください。これは、ブランチのコストではあるが、割り当て解除のコストを無効にすることがよくあります。

+7

コンパイラが移動代入をインライン化してデッドストアを削除することはできませんか? – u0b34a0f6ae

+7

私はコンパイラエンジニアではありません。私はそれが可能だと思いますが、私は確かに分かりません。私はそれに頼ることを躊躇しています。一日の終わりには、両方の方法とテストをコーディングする必要があります。テストで 'std :: swap'と同じ速さであることが示された場合、その結果はコンパイラ/プラットフォームに依存する可能性があります。また、アプリケーションがパフォーマンス重大な領域で 'スワップ 'しない場合、' std :: swap'が邪悪な速さの2倍の遅さであるかどうかは気にしません。 –

+1

パーティーに少し遅れてしまいました...しかし、私は簡単な疑問を持っています:Move Assignmentはなぜ2Loads + 2Store(Move Constructorより1 Load多い)を占めているのですか?それは "それを返す*"をしなければならないからですか?または、それを再割り当てする前に所有するポインタを "削除"する暗黙の必要性のために、それは削除式で読み取られる必要がありますか? – abigagli

0

あなたのタイプによって異なります。

xからz、yからx、zからyに移動します。それは基本的な表現の3つのコピー操作です(おそらく1つのポインタ、多分もっと多くの人が知っています)

おそらく、あなたのタイプの高速スワップを作成することができますあなたの基になる型のスワップは速いです)。

また、コンパイラが最適化をうまく行っていて、本質的に両方のケースを同じ命令(レジスタ内の一時的なもの)に最適化します。

私は個人的には、移動割り当てのようなものを含め、いくつかの場所から呼び出されるスワップメンバ関数を実装する傾向がありますが、YMMVです。

0

このswap()は、移動コンストラクタと2つの移動割り当てを呼び出します。私は1つが関係なく、移動コンストラクタと代入演算子の実装の、のようなクラスの彼の特定のタイプの

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); 
    } 
}; 

をより効率的swap()を書くことができると思います。

+0

コピーコンストラクタはどこですか?より効率的なスワップの例を教えてください。 – ronag

+0

@ronag:申し訳ありませんが、私の間違いです。 –

2

私は移動セマンティクスがあるので、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); } 
} 
+3

'swap'を使う正しい方法は、' std :: swap'を使い、 'swap'を非修飾呼び出しすることです。また、 'std :: swap'を専門にすることは、関数を部分的に特殊化することができないため、Not So Good™と見なされます。詳細については、[この回答の回答](http://stackoverflow.com/questions/6380862/how-to-provide-a-swap-function-for-my-class/6380882#6380882)を参照してください。 – Xeo

+0

名前空間stdに何かを追加できますか? –

+2

@MichaWiedenmann、上記の例のようにstd関数のテンプレート特殊化を追加することができます – utnapistim

関連する問題