4

効果的な C++ 3/Eで、私はこれを読みました:

これは、例外的に安全でないコードです。

class Test { };
void foo(const std::shared_ptr<Test> &ptr, int i);
int bar();
...

foo(std::shared_ptr<Test>(new Test), bar());

コンパイラは次のように実装できるため:

  1. 走るnew Test
  2. call bar() <--bar()が例外をスローした場合、by によって割り当てられたオブジェクトは削除Testできnew Testません。
  3. のコンストラクターを呼び出すstd::shared_ptr<Test>
  4. 電話foo()

ただし、この場合、コンパイラはメモリ リークがあることを認識できます。delete例外がスローされた場合、コンパイラは自動的に実行できませんか?

さらに、deleteその場合、コンパイラは自動的に次のことを行います。

Test *p = new Test;

これは次のように実装されます:

  1. operator newメモリを割り当てる呼び出し
  2. のコンストラクタを呼び出しますTestコンストラクターが例外をスローした場合、メモリは自動的に削除されます。

2番目のケースとは異なり、最初のケースでコンパイラが機能しないのはなぜですか?

4

1 に答える 1

4

通常、コンパイラはメモリ リークがあることを認識できません。コードが のコンストラクターから返されるとTest、コンパイラーは、オブジェクトが完全かつ正しく構築されたと想定する必要があります。これは、コンストラクターがオブジェクトへのポインターをどこかに登録したことを意味し、他のコードがそれ。

標準では、例外が通過する完全な式で newed されたすべてのオブジェクトで例外が呼び出されるように指定 できます。deleteこれが考慮されなかったのには、多くの歴史的な理由があります。そして今日、それはおそらく既存のコードをあまりにも多く破壊するでしょう.

標準では、式の評価に厳密な順序付けを課すこともできました。これにより、未定義の動作に関する多くの問題が解消され、コードがより決定論的になります (テストの信頼性が向上します)。歴史的に、C は最適化への影響のため、このルートを取りませんでした。C++ はルールを守っています。

于 2014-04-25T10:58:42.633 に答える