2

これは、libstdc++ の new 演算子の実装です。

_GLIBCXX_WEAK_DEFINITION void *
operator new (std::size_t sz) _GLIBCXX_THROW (std::bad_alloc)
{
  void *p;

  /* malloc (0) is unpredictable; avoid it.  */
  if (__builtin_expect (sz == 0, false))
    sz = 1;

  while ((p = malloc (sz)) == 0)
    {
      new_handler handler = std::get_new_handler ();
      if (! handler)
        _GLIBCXX_THROW_OR_ABORT(bad_alloc());
      handler ();
    }

  return p;
}

コンストラクターの例外が割り当てられたメモリを解放することを誰が保証しますか?

Upd:コメンテーターに感謝します - 実際には、新しい式の例外安全性を意味していました。

4

1 に答える 1

5

質問に「new expression」と「operator new」が混在しています。

新しい式は次のようになります: A* a = new A(); C++ 言語は、この式が次のように評価されることを定義します (過度に単純化された疑似コード):

void* __a = operator new(sizeof(A));
try {
   A::A(this = static_cast<A*>(__a));
} catch (...) {  operator delete (__a); throw; }

ご覧のとおり、例外が発生するとメモリの割り当てが解除されます。

より詳細な説明:

初期化が (コンストラクターなどから) 例外をスローして終了した場合、new-expression がストレージを割り当てた場合、適切な解放関数を呼び出します: 非配列型の operator delete、配列型の operator delete[]。


コンパイラによって実際に生成されたコードについては、こちらを参照してください。ソース コードに含まれていない場合でも、演算子 delete の呼び出しに気付く場合があります。

struct A { A(); };
A::A() { throw 13; }

int main()
{
    auto a = new A();
}

アセンブラ:

 call 401040 <operator new(unsigned long)@plt>
...
 call 401172 <A::A()>
...
 call 401050 <operator delete(void*, unsigned long)@plt>
...
 call 401080 <_Unwind_Resume@plt>
于 2020-12-10T13:56:00.517 に答える