11

次のようなテンプレートがあります。

template<typename T>
struct foo {
  T m_t;
  foo(T t) : m_t(t) {}
};

問題は、小さい/通常の型と巨大な型 (行列など) の両方をサポートしたいということですT。このようにコンストラクタ初期化子リストを書くことをお勧めしますか

foo (T t) : m_t(std::move(t)) {}

より小さな型であっても、型Tが常にムーブ構築をサポートすることを要求しますか? より良い方法はありますか?

4

3 に答える 3

12

小さい型であっても、型 T が常に move 構築をサポートする必要がありますか?

コピー構築可能な型は、ムーブ構築可能でもあります。このような場合の移動は、単純にコピー コンストラクターを呼び出します。したがって、使用しない理由はありませんm_t(std::move(t))

別の方法は、代わりに参照を使用することです。

foo (T const& t) : m_t(t) {}
foo (T&& t) : m_t(std::move(t)) {}

これには、2 つではなく 1 つの構成のみが含まれるという利点があります。

于 2013-06-10T23:01:17.950 に答える
8

はい、その場合、わざを使用しても何の不利益もありません。コピー可能なオブジェクトはすべて自動的に移動可能であるため、問題ありません。実際、整数であっても、可能であれば常に変数を移動することを推奨する人もいます。

別の方法として、この回答で説明されているように、完全転送の使用を検討できます。

template <typename T2>
foo(T2&& t) : m_t(std::forward<T2>(t)) {}

が fast move コンストラクターを定義していることがわかっている場合T、それは問題ではありません。foo(const T&)それ以外の場合は、不要なコピーを避けるために、コンストラクターを提供することをお勧めします。

完全転送は、それを実現するための 1 つの手法にすぎません。もちろん、コンストラクタを書き出す Pubby のソリューションも問題foo(const T&)ありません。foo(T&&)結果は同じですが、主にスタイルの問題です。

小さな整数型についても質問しました。理論的には、参照渡しはコピーよりも遅くなりますが、コンパイラはそれをコピーに最適化できるはずです。違いはないと思います。

Tしたがって、巨大になる可能性があり、高速な移動コンストラクターを提供しない最悪のケースを最適化することをお勧めします。参照渡しはそのような状況に最適であり、一般的に悪い選択ではありません。

于 2013-06-10T23:19:49.187 に答える
0

値による受け渡しには、コンストラクターが 1 つしかない (テンプレートを使用しない) という利点がありますが、前述の代替方法と比較して、移動の構築が 1 つ増えるという代償があります。

ただし、値渡しと Pubby によって提供される非テンプレート ソリューションの両方には、まだ言及されていない別の欠点がありますT(T&);。右辺値参照は左辺値参照から const にバインドできますが、左辺値参照から非定数にはバインドできないため、コンパイラはコピー コンストラクターを呼び出すことができません。

この問題を解決するには、foo (T & t) : m_t(t) {}Pubby のソリューションに 3 つ目のオーバーロードを追加するだけです。

于 2016-08-18T15:12:57.980 に答える