1

私はこれをまっすぐにする必要があります。以下のコードを使用すると、次のようになります。

vector<unsigned long long int> getAllNumbersInString(string line){
    vector<unsigned long long int> v;   
    string word;
    stringstream stream(line);
    unsigned long long int num;

    while(getline(stream, word, ',')){
    num = atol(word.c_str());
    v.push_back(num);
    }

    return v;
}

このサンプル コードは、入力文字列をベクトルに格納された一連の unsigned long long int に変換するだけです。

上記の場合、この関数を呼び出す別の関数があり、ベクトルに約 100,000 の要素があるように見える場合、これは、それを返すと、新しいベクトルが作成され、要素が同じように作成されることを意味しますか?関数内で、関数内の元のベクトルは戻るときに削除されますか? これまでの私の理解は正しいですか?

通常、コンテナーに関してはすべての関数がポインターを返すようにコードを記述しますが、プログラムの設計上、および上記の私の理解では、コンテナーに関しては常にポインターを返す必要がありますか?

4

4 に答える 4

8

ほとんどのstd::vector場合 (コンパイラの最適化がオンになっている場合)、関数の戻り値で直接構築されます。これは copy/move elision として知られており、コンパイラが実行できる最適化です。

クラスの戻り値の型を持つ関数の return ステートメントで、式が関数の戻り値の型と同じ cv-unqualified 型を持つ不揮発性自動オブジェクト (関数または catch-clause パラメーター以外) の名前である場合、自動オブジェクトを関数の戻り値に直接構築することにより、コピー/移動操作を省略できます

この引用は C++11 標準から取られていますが、C++03 についても同様です。コピー/移動省略はまったく発生する必要がないことに注意することが重要です。これは完全にコンパイラ次第です。最新のコンパイラのほとんどは、あなたの例をまったく問題なく処理します。

省略が発生しない場合でも、C++11 は C++03 よりも優れた利点を提供します。

  • C++03 では、コピーの省略std::vectorがなければ、このような a を返すと、あなたが言うように、返されたオブジェクトにすべての要素をコピーしてから local を破棄する必要がありましたstd::vector

  • C++11 では、は関数の外std::vector移動されます。移動すると、返されたオブジェクトが破壊されようとしているコンテンツstd::vector盗むことができます。std::vectorこれは、コンテンツをコピーするよりもはるかに効率的です。

    左辺値であるため、オブジェクトがコピーされるだけだと予想したかもしれませんが、このようなコピーを最初に移動と見なす特別なルールがあります。

    コピー操作の省略の基準が満たされ [...]、コピーされるオブジェクトが左辺値で指定されている場合、オブジェクトが右辺値で指定されているかのように、コピーのコンストラクターを選択するためのオーバーロード解決が最初に実行されます。

コンテナーへのポインターを返す必要があるかどうかについては、答えはほぼ間違いなくノーです。完全に必要な場合を除き、ポインターを渡すべきではありません。必要な場合は、スマート ポインターを使用する方がはるかに優れています。これまで見てきたように、あなたのケースでは、値渡しのオーバーヘッドがほとんどまたはまったくないため、まったく必要ありません。

于 2013-02-09T15:37:43.457 に答える
4

適切なコンパイラを使用して値を返すことは安全であり、好ましいと言えます。C++ 標準では、この場合は戻り値の最適化(NRVO)という名前のコピー省略が許可されています。これは、心配しているこの余分なコピーが行われないことを意味します。

これは、プログラムの観察可能な動作を変更できる最適化のケースであることに注意してください。

注2.他の回答で述べたように、C++ 11は移動セマンティクスを導入しています。つまり、RVO適用されない場合でも、返されるオブジェクトの内容が転送される非常に安価な操作が必要になる場合があります。呼び出し側。の場合std::vector、これは非常に安いです。ただし、すべてのタイプを移動できるわけではないことに注意してください。

于 2013-02-09T15:36:09.440 に答える
2

あなたの理解は正しいです。
ただし、コンパイラはRVO および NRVOを介してコピー省略を適用し、生成される余分なコピーを削除できます。

コンテナーに関しては、常にポインターを返す必要がありますか?

可能であれば、もちろん、特に非 POD タイプの場合は、値による戻りを避ける必要があります。

于 2013-02-09T15:35:50.930 に答える
2

それは、参照セマンティクスが必要かどうかによって異なります。

一般に、参照セマンティクスが必要ない場合は、ポインターを使用しないでください。これは、C++11 コンテナー クラスではムーブ セマンティクスがサポートされているため、コレクションを値で返すのが高速であるためです。また、コンパイラは、移動されたコンストラクターへの呼び出しを省略できるため (これは名前付き戻り値の最適化または NRVO と呼ばれます)、オーバーヘッドがまったく発生しません。

ただし、たとえば、返されたベクターへの挿入がそのベクターの所有権を共有するいくつかの場所で「見られる」ように、コレクションの一貫した個別のビュー (つまりエイリアス)を作成する必要がある場合は、返すことを検討する必要があります。スマートポインター。

于 2013-02-09T15:36:14.690 に答える