33

std :: vector(または他のSTLコンテナ)に入力したい:

class Foo {
public:
  Foo(int _n, const Bar &_m);
private:
  std::vector<Foo> fooes_;
}

1.格好良いctor、高価なパフォーマンス

std::vector<Foo> get_vector(int _n, const Bar &_m) {
  std::vector<Foo> ret;
  ... // filling ret depending from arguments
  return ret;
}

Foo::Foo(int _n, const Bar &_m) : fooes_(get_vector(_n, _m) {}

2.パフォーマンスが向上し、見栄えの悪いctor

void fill_vector(int _n, const Bar &_m, std::vector<Foo> &_ret) {
  ... // filling ret depending from arguments
}

Foo::Foo(int _n, const Bar &_m) { fill_vector(_n, _m, fooes_); }

get_vector冗長なコピーやコンストラクター呼び出しを回避するために、C ++ 0x(セマンティクス機能の移動など)を使用して最初の例から関数を書き直すことは可能ですか?

4

3 に答える 3

46

C ++ 0x互換のコンパイラと標準ライブラリを使用している場合は、何もしなくても最初の例からパフォーマンスが向上します。の戻り値get_vector(_n, _m)は一時的なものであり、のmoveコンストラクターstd::vector(右辺値参照を取得するコンストラクター)は自動的に呼び出され、それ以上の作業は必要ありません。

一般に、ライブラリ以外のライターは、右辺値参照を直接使用する必要はありません。メリットのかなりの部分を自動的に享受できます。

于 2011-06-02T07:17:46.363 に答える
16

(1)と(2)は、コンパイラが名前付き戻り値の最適化を実行する限り、C ++ 0xがなくても同じパフォーマンスを発揮すると思います。これは、ほとんどの場合に実行されると思います。コピーも移動もしないでください。

私が間違っている場合は、NRVOを誤解しているので、訂正してください。

于 2011-06-02T08:01:05.580 に答える
7

検討している特定のケースでは、最初の実装は2番目の実装と同じくらい効率的です。retコンパイラーは、関数内のコピーをget_vector戻り値に最適化し、 moveセマンティクスを使用して、ベクトルの所有権をコンテナークラスに転送します。ベクトルでの移動の構築には、コンテナー内の要素の数とサイズに関係なく、3つのポインターコピーが必要です(実装に依存しますが、適切な概算です)。変更する参照としてベクターを渡すには、単一のポインターコピーが必要です(再度おおよそのコスト)が、ベクターに対して実行する操作は、どちらのオプションのコストも支配します。

変更のためにベクトルを関数に渡す方が速い場合がある非常に特殊な状況がいくつかありますが、それらはまれであり、ベクトル自体よりもドメインに関連しています。それを無視して、保守性のために最初にコーディングし、プログラムが遅い場合は、プロファイルを作成し、プログラムのコストがどこにあるかを判断してから、最適化を検討してください。興味深いのは、プロファイルを作成したら、おそらくボトルネックが何であるかを知っていることです。つまり、何を変更するかについてのヒントが得られるということです。

于 2011-06-02T07:27:15.847 に答える