何かを「投げる」とき、それはメモリのどこに保存されますか?


82

何かがthrownの場合、スタックはキャッチされるまで「巻き戻され」、各関数コンテキストのスタック上のクラスインスタンスのデストラクタが実行されることを理解しています(そのため、デストラクタから例外をスローしないでください)。 -あなたは2番目のものを投げることになるかもしれません)...しかし、これが起こっている間、私が投げたオブジェクトはメモリのどこに保存されているのだろうか?

実装に依存しますか?もしそうなら、最も人気のあるコンパイラで使用される特定の方法はありますか?


1
良い質問です。標準ではスタックが必要であるとさえ言われていないため、おそらく標準では指定されていません。実際には、おそらくそれはヒープに割り当てられ、catchブロックが終了したときに解放されますか?
Kerrek SB 2011

@Kerrek:おそらく、オブジェクトはスタックの「一番下」に配置されていると思います。次に、それがどこにあったかを思い出しながら上向きに巻き戻し、巻き戻しが終了したら(catch句に参照によって例外に対処し、それを再実行する機会を与えることを含むraise)、それを破棄します。ヒープ割り当ての問題は、例外を割り当てる試みが失敗した場合、どうしますか?中止する必要があります(スペース不足のためにスタックに置くことが「失敗」した場合のスタックオーバーフローの場合と同じように)。Javaとは異なり、実装では代わりに別の例外をスローすることはできません。
スティーブジェソップ2011

@Steve:可能性もあります-Kirilの記事によると、例外はスタックに割り当てられ、補助情報構造はそのアドレスや削除者などを記録しますが、実装はこれを好きなように自由に行うことができると思いますか?
Kerrek SB 2011

@Kerrek:はい、実際に例外をスローする必要があるという制約があります。スタックが不足すると、実装はそのような責任を回避できます:-)スタックに置くと、例外がスローされるためです。throw式の静的型により、関数全体のスタックフレームには、その型をスローするために必要なスペースを含めることができますが、MSVCがそれを行うかどうかはわかりません。
スティーブジェソップ2011

回答:


51

はい、答えはコンパイラに依存します。

私のコンパイラ(g++ 4.4.3)を使った簡単な実験では、ランタイムライブラリが最初mallocに例外のメモリを試み、それが失敗すると、データセグメント上にあるプロセス全体の「緊急バッファ」内にスペースを割り当てようとすることがわかります。それがうまくいかない場合は、を呼び出しますstd::terminate()

緊急バッファの主な目的は、std::bad_allocプロセスがヒープスペースを使い果たした後にスローできるようにすることであるように見えます(この場合、malloc呼び出しは失敗します)。

関連する機能は__cxa_allocate_exception次のとおりです。

extern "C" void *
__cxxabiv1::__cxa_allocate_exception(std::size_t thrown_size) throw()
{
  void *ret;

  thrown_size += sizeof (__cxa_refcounted_exception);
  ret = malloc (thrown_size);

  if (! ret)
    {
      __gnu_cxx::__scoped_lock sentry(emergency_mutex);

      bitmask_type used = emergency_used;
      unsigned int which = 0;

      if (thrown_size > EMERGENCY_OBJ_SIZE)
        goto failed;
      while (used & 1)
        {
          used >>= 1;
          if (++which >= EMERGENCY_OBJ_COUNT)
            goto failed;
        }

      emergency_used |= (bitmask_type)1 << which;
      ret = &emergency_buffer[which][0];

    failed:;

      if (!ret)
        std::terminate ();
    }

  // We have an uncaught exception as soon as we allocate memory.  This
  // yields uncaught_exception() true during the copy-constructor that
  // initializes the exception object.  See Issue 475.
  __cxa_eh_globals *globals = __cxa_get_globals ();
  globals->uncaughtExceptions += 1;

  memset (ret, 0, sizeof (__cxa_refcounted_exception));

  return (void *)((char *)ret + sizeof (__cxa_refcounted_exception));
}

このスキームがどれほど典型的かはわかりません。


「その場合、malloc呼び出しは失敗します」通常、ただし必ずしもそうとは限りません。
Ayxan Haqverdili

20

このページから:

例外がスローされるためにストレージが必要です。このストレージは、ハンドラーによって使用されるため、スタックが巻き戻されている間も存続する必要があり、スレッドセーフである必要があります。したがって、例外オブジェクトストレージは通常、ヒープ割り当てられますが実装では、メモリ不足の条件下でbad_alloc例外のスローをサポートする緊急バッファが提供される場合があります

現在、これはItanium ABIのみであり、GCC、Clang、およびMSVCに固有の詳細を探しています。ただし、標準では何も指定されておらず、これは例外ストレージを実装するための明白な方法のようです。


1
まだ詳細をお探しですか?複数の回答を受け入れることができれば便利な場合があります:)
sje397 2011

4

これがあなたの質問に答えるかどうかはわかりませんが、これ(C ++コンパイラが例外処理を実装する方法)は、例外処理に関する優れた記事です。私はそれを強くお勧めします(:

短い答えで申し訳ありませんが、記事のすべての情報は素晴らしいです、私はここでいくつかの情報を選んで投稿することはできません。


excpt_infoそのページで検索すると、MSVCがどのようにそれを行うかについての情報が得られます。
スティーブジェソップ2011

1
そのリンクは、良い実装でそれを行わない方法を実際に説明しています。古いVC ++がこのようなものを使用していることは知っていますが、最近のコンパイラで見つかるとは思えません。
James Kanze 2011

0

C ++標準は通常、言語の動作を指定しますが、コンパイラがその動作を実装する方法は指定しません。この質問はそのカテゴリに分類されると思います。このようなものを実装する最良の方法は、マシンの詳細によって異なります。一部のプロセッサには多くの汎用レジスタがあり、一部には非常に少ないものがあります。プロセッサは、例外のためだけに特殊レジスタを使用して構築される場合もあります。その場合、コンパイラはその機能を自由に利用できるはずです。


-2

まあ、それは巻き戻されるのでスタックに置くことはできませんし、ヒープに置くこともできませんstd::bad_alloc。それはシステムがスローできない可能性があることを意味するからです。それ以外は、完全に実装次第です。実装は指定されていません(文書化する必要があります)が、指定されていません。(実装は、メモリがなくなった場合でも限られた数の例外を許可する何らかの緊急バックアップがある限り、ほとんどの場合ヒープを使用できます。)


3
あなたの答えはそれ自体と矛盾しています。
軌道上でのライトネスレース

どうやって?これは、標準に暗黙的に含まれている実装の制約を示しています。
James Kanze 2011

一例:「ヒープ上に置くことはできません」...「実装はほとんどの場合ヒープを使用できます」。さらに、他の回答で説明されているように、回答の前半全体が間違っています(実際、部分的にあなたの後半で!)。
軌道上でのライトネスレース2011年

標準は機能する必要がありstd::bad_allocます。これは、実装がヒープを体系的に使用できないことを意味します。標準では許可されていません。私は自分の主張を標準に基づいています。
James Kanze 2011

「体系的に」のFSVO、それは正しいです。ただし、回答の2番目の部分で述べているように、実装では実際にheap ^ H ^ H ^ H ^ Hfreestoreを代替手段と組み合わせて使用​​できます。
軌道上でのライトネスレース2011年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.