1

重複の可能性:
C ++では、関数からベクトルを返すことはまだ悪い習慣ですか?

パフォーマンスの観点から、関数のようなstd::vector、または関数から「重い」オブジェクトを返す必要がある場合は、次の形式を使用することをお勧めしますstd::string

void func(std::vector<int> *dest)
{
}

この形式の代わりに:

std::vector<int> func()
{
    std::vector<int> arr;
    // ...
    return arr;
}

最初のフォームの方が高速であると思いますが、同時に2番目のフォームを何度も見てきましたが、Qt APIは、QStringたとえば、はるかに便利で直感的に使用できるため、たとえばを返すことがよくあります。

また、returnステートメントを使用するときにオブジェクトの不要なコピーを削除できるコンパイラの最適化があるかどうか疑問に思いました。


編集

回答に記載されている最適化を実行しない、今日でも使用されている人気のあるコンパイラはありますか?

4

4 に答える 4

7

[値による戻り]の代わりに[ポインタによる受け渡し]を使用することをお勧めしますか?

いいえ

最新のC++コンパイラは、名前付き戻り値最適化(NRVO)を実行します。これは、コンパイラがここでコピーを確実に排除することを効果的に意味します。コピーは実行されません。

これは、使用しているC++のバージョンに関係ないことに注意してください。C++03はC++11と同様に機能します。C ++ 11で変更された唯一の点は、コピーの省略を実行できない場合に、ライブラリが値からの移動(ここで行われているように)を効率的に行えるようにすることです。

戻り値の場合、通常はコピーの省略を実行できます。他の場合(たとえば、パラメーターを値で渡す場合)の方が適切です。ただし、例外があります。次のコードでは、名前付き戻り値の最適化を使用できません。ただし、C++11の移動を使用できます。

std::string foo() {
    std::string one = "Foo";
    std::string two = "Bar";

    if (rand() % 2 == 0)
        return one;
    else
        return two;
}

その理由は、2つのコードパスが異なる名前のオブジェクトを返すようになったためです。これにより、NRVOが防止されます。

于 2013-01-22T18:20:46.323 に答える
3

値で返す:

std::vector<int> func();

C ++では、このような状況でのコピーの省略が可能であり、それを超えると、新しいC ++で定義された移動セマンティクスにより、これらの操作が安価になります。コンパイラは一般的にこれをうまく実装します。(コピーの省略を使用すると、ローカルarrは実際には受信者の呼び出しサイト変数に直接構築されます。この状況は「戻り値の最適化」とも呼ばれます。)

于 2013-01-22T18:20:29.673 に答える
2

RVOとNRVOを許可するルールはARM(1990)に存在していたため、コンパイラーがそれらを実装していなかったとしたら驚くでしょう。

さらに重要なことに、パラメーター(ポインターまたはnon-constへの参照)を使用することは非常に扱いにくいです。プロファイラーが戻り値のコピーのために本当に時間の問題を抱えていると言うまで、それをしないでください。その時点で、次の行に沿って関数をオーバーロードします。

void func( std::vector<int>& dest )
{
    //  ...
}

std::vector<int> func()
{
    std::vector<int> results;
    func( results );
    return results;
}

次に、プロファイラーが問題を抱えていると言った場所で両方を試して、問題を解決するものを選択します(違いが生じる場合)。

私は実際に一度これをしなければなりませんでしたが、それは1991年か1992年頃のことでした。それ以来、私はそれをする必要はありませんでした。私たちは今でも定期的に帰国するstd::vectorか、社内のMatrixクラスに参加しています。すべての対象コンパイラがC++11をサポートしているわけではないため、C++11の利点はありません。

于 2013-01-22T18:50:39.560 に答える
1
std::vector<int> func();

C ++ 11では、上記が関数になります。関数が戻ると、ローカルstd::vectorオブジェクトが移動します。可能であれば、コンパイラーは移動さえも排除できます。

要するに、心配する必要はありません。値で返します。

于 2013-01-22T18:20:39.910 に答える