0

のは、我々は次のコードスニペットを持っていると仮定しましょう:関数パラメータの内部実行順序は定義されていますか?

void foo(std::unique_ptr<Data> p1, std::unique_ptr<Data> p2){ 
    bar(p1); 
    bar(p2); 
} 

int main(){ 
    foo(std::unique_ptr<Data>{new Data}, std::unique_ptr<Data>{new Data}); 
} 

質問は次のとおりです。メモリは、常にこのコードを実行している時に解放されます(関係なく、何が起こりますか)?

標準では、関数の引数であるステートメントの順序に依存することはできませんが、内部関数呼び出し/メモリ割り当てなどはどうですか?ここでも重要ですか?

答えて

7

このコードを実行すると、いつでもメモリが解放されます(何が起こっても問題ありません)。いいえ:C++ 17前

。実行の一つの潜在的順序は次のとおりです。

  1. が右new Data
  2. unique_ptrコンストラクタ(1)スローした場合、我々はOKだ

  • unique_ptrコンストラクタを左new Data
  • を残しました。 (2)がスローされた場合、まだ実際にはunique_ptrコンストラクタを実行していないため、(1)からメモリを解放するクリーンアップメカニズムはありません。それは漏れるだろう。 (1)も(2)も投げられない場合にのみ、私たちは大丈夫です。

    標準はstd::make_uniqueを導入する理由です:この問題はありません

    foo(std::make_unique<Data>(), std::make_unique<Data>()); 
    

    からnew Sは現在、内部でunique_ptrコンストラクタにグループ化されています。もし成功すれば、すでにRAIIガードに包まれているでしょう。


    後にC++ 17:はい。関数の引数の評価順序は未定ですが、そのような評価はインターリーブできないという新しい規則があります。つまり、f(g(a), h(b))を指定すると、潜在的な評価順序は[f, g, a, h, b][f, h, b, g, a]です。 abの両方をgまたはhの前に評価することはもはや不可能であり、元のコードの潜在的な問題でした。

  • +0

    投げることができるコンストラクタを持つことは悪い習慣ではありませんか? – user3853544

    +0

    @ user3853544 'operator new'は投げることができます – Caleth

    +0

    @ user3853544依存しています:オブジェクトを有効な状態にしたい(構築せずに、それらが有効であるかどうかを確認する)場合は、このために使用することができます。 – Patryk

    関連する問題