C++ で bad_alloc に対処するにはどうすればよいですか?
-
13-11-2019 - |
質問
という方法があります foo
次のエラーが返されることがあります。
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Abort
を使用できる方法はありますか? try
-catch
このエラーでプログラムが終了するのを防ぐためにブロックします (私がやりたいのは返すことだけです) -1
)?
もしそうなら、その構文は何ですか?
他にどう対処すればよいでしょうか bad_alloc
C++で?
解決
他の例外のようにキャッチすることができます:
try {
foo();
}
catch (const std::bad_alloc&) {
return -1;
}
.
あなたがこの時点からあなたができることはあなた次第ですが、それは間違いなく技術的に実行可能です。
他のヒント
一般にはではありません。を試してはいけません。 bad_alloc
は、さまざまなためにリソースが割り当てられないことを示します。十分なメモリがあります。ほとんどのシナリオで、あなたのプログラムはそれに対処することを望み、すぐに終了することは唯一の意味のある行動です。
悪い、最新のオペレーティングシステムはしばしばオーバー割り当て:そのようなシステムでは、malloc
とnew
が有効なポインタが残っていなくても、std::bad_alloc
は決してスローされることはできません。疲弊。代わりに、 Access を試みると、割り当てられたメモリはセグメンテーション障害をもたらします。これはキャッチ可能なものではありません( handle セグメンテーション障害信号ができますが、その後プログラムを再開することはできません。 )
std::bad_alloc
をキャッチするときにできるだけのことは、おそらくエラーを記録し、優れたリソースを解放することによって安全なプログラムの終了を確実にすることを試みることです(ただし、これはエラーがスローされた後に巻き戻しの通常のコースで自動的に行われます。プログラムは適切にRAIIを使用します。
特定の場合には、プログラムはいくつかのメモリを解放して再試行するか、またはRAMの代わりに二次メモリ(= Disk)を使用しようとしますが、これらの機会は厳密な条件を持つ非常に具体的なシナリオでのみ存在します。
- メモリを介していないシステムで実行されていることを確認する必要があります。つまり、割り当て時に障害が発生しないようにする必要があります。後でより
- アプリケーションは、その間にさらに偶然の割り当てを除いて、メモリをすぐに解放できなければなりません。
アプリケーションがポイント1 - USERSPACEアプリケーションを制御することが非常にまれです。 do do、それは変更するためのroot権限を必要とするシステム全体の設定です。 1
OK、あなたが固定したことを想定しましょう。="nofollow noreferrer"> LRU Cache 一部のデータ(おそらく、再生成またはオンデマンドでリロードできるいくつかの特に大きなビジネスオブジェクト)について。次に、再試行をサポートする関数に失敗する可能性がある実際のロジックを置く必要があります。言い換えれば、それが中止されたら、それを再起動することができます。
.lru_cache<widget> widget_cache; double perform_operation(int widget_id) { std::optional<widget> maybe_widget = widget_cache.find_by_id(widget_id); if (not maybe_widget) { maybe_widget = widget_cache.store(widget_id, load_widget_from_disk(widget_id)); } return maybe_widget->frobnicate(); } … for (int num_attempts = 0; num_attempts < MAX_NUM_ATTEMPTS; ++num_attempts) { try { return perform_operation(widget_id); } catch (std::bad_alloc const&) { if (widget_cache.empty()) throw; // memory error elsewhere. widget_cache.remove_oldest(); } } // Handle too many failed attempts here.
しかし、ここでも、
std::set_new_handler
を処理する代わりにstd::bad_alloc
を使用すると同じ恩恵があり、はるかに簡単です。
1 がのコントロールポイント1であるアプリケーションを作成している場合は、この答えを読んで、私にEメールを撮影してください、私は本当に興味がありますあなたの状況について
C++ 標準で指定されている動作は何ですか? new
C++で?
通常の考え方は、次のとおりです。 new
オペレーターは要求されたサイズの動的メモリーを割り当てることができない場合、次のタイプの例外をスローする必要があります。 std::bad_alloc
.
しかし、その前にさらに何かが起こります。 bad_alloc
例外がスローされます:
C++03 セクション 3.7.4.1.3: 言う
ストレージの割り当てに失敗した割り当て関数は、現在インストールされている new_handler(18.4.2.2) を呼び出すことができます (存在する場合)。[注記:プログラムが提供する割り当て関数は、set_new_handler 関数 (18.4.2.3) を使用して、現在インストールされている new_handler のアドレスを取得できます。] 空の例外仕様 (15.4) で宣言された割り当て関数 throw() がストレージの割り当てに失敗した場合、 null ポインタを返すものとします。ストレージの割り当てに失敗した他の割り当て関数は、クラス std::bad_alloc (18.4.2.1) または std::bad_alloc から派生したクラスの例外をスローすることによってのみ失敗を示します。
次のコードサンプルを考えてみましょう。
#include <iostream>
#include <cstdlib>
// function to call if operator new can't allocate enough memory or error arises
void outOfMemHandler()
{
std::cerr << "Unable to satisfy request for memory\n";
std::abort();
}
int main()
{
//set the new_handler
std::set_new_handler(outOfMemHandler);
//Request huge memory size, that will cause ::operator new to fail
int *pBigDataArray = new int[100000000L];
return 0;
}
上の例では、 operator new
(おそらく) 100,000,000 個の整数にスペースを割り当てることができなくなり、関数 outOfMemHandler()
が呼び出され、その後プログラムは中止されます。 エラーメッセージを発行しています。
ここで見られるように、デフォルトの動作は new
メモリ要求を満たすことができない場合、オペレータは、 new-handler
十分なメモリが見つかるか、新しいハンドラーがなくなるまで、関数は繰り返し実行されます。上の例では、呼び出さない限り、 std::abort()
, outOfMemHandler()
だろう 繰り返し呼ばれる. 。したがって、ハンドラーは次の割り当てが成功することを確認するか、別のハンドラーを登録するか、ハンドラーを登録しないか、リターンしないかのいずれかを行う必要があります。プログラムを終了します)。新しいハンドラーがなく、割り当てが失敗した場合、オペレーターは例外をスローします。
とは何ですか new_handler
そして set_new_handler
?
new_handler
何も受け取らず何も返さない関数へのポインタの typedef であり、 set_new_handler
を受け取って返す関数です。 new_handler
.
何かのようなもの:
typedef void (*new_handler)();
new_handler set_new_handler(new_handler p) throw();
set_new_handler のパラメータは関数演算子へのポインタです。 new
要求されたメモリを割り当てられない場合は呼び出す必要があります。その戻り値は、以前に登録されたハンドラー関数へのポインター、または以前のハンドラーがなかった場合は null です。
C++ でメモリ不足状態を処理するにはどうすればよいですか?
の動作を考えると、 new
適切に設計されたユーザー プログラムは、適切な機能を提供することでメモリ不足状態を処理する必要があります。 new_handler
これは次のいずれかを実行します。
より多くのメモリを利用できるようにします。 これにより、演算子 new のループ内での次のメモリ割り当て試行が成功する可能性があります。これを実装する 1 つの方法は、プログラムの起動時に大きなメモリ ブロックを割り当て、その後、new-handler が最初に呼び出されたときにプログラム内で使用するためにそのブロックを解放することです。
別の new ハンドラーをインストールします。 現在の new-handler がこれ以上メモリを利用可能にすることができず、それができる別の new-handler がある場合、現在の new-handler はその場所に他の new-handler をインストールできます (呼び出しによって)。 set_new_handler
)。次回、演算子 new が new-handler 関数を呼び出すと、最後にインストールされた関数が取得されます。
(このテーマのバリエーションは、new-handler が自身の動作を変更することで、次回呼び出されたときに別のことを実行します。これを実現する 1 つの方法は、new ハンドラーの動作に影響を与える静的データ、名前空間固有のデータ、またはグローバル データを new ハンドラーに変更させることです)。
new-handler をアンインストールします。 これは、null ポインタを渡すことによって行われます。 set_new_handler
. 。new-handler がインストールされていない場合、 operator new
例外をスローします ((に変換可能) std::bad_alloc
) メモリの割り当てが失敗した場合。
例外をスローする に変換可能 std::bad_alloc
. 。このような例外は、次の方法ではキャッチされません。 operator new
, ですが、メモリの要求を送信したサイトに伝播します。
返さない: 電話することで abort
または exit
.
bad_alloc
はあなたがメモリのうちであることを意味しますので、これを示唆しません。回復しようとする代わりにあきらめるだけでよいでしょう。しかし、ここにあなたが求めている解決策です:
.try {
foo();
} catch ( const std::bad_alloc& e ) {
return -1;
}
私はこれにより単純な(そしてさらに速い)解を提案するかもしれません。メモリを割り当てることができなかった場合、new
演算子はNULLを返します。
int fv() {
T* p = new (std::nothrow) T[1000000];
if (!p) return -1;
do_something(p);
delete p;
return 0;
}
.
これが役立つことを願っています!
あなたの fooプログラム exit 道:
.
#include <stdlib.h> /* exit, EXIT_FAILURE */
try {
foo();
} catch (const std::bad_alloc&) {
exit(EXIT_FAILURE);
}
実際のプログラムを呼び出すシェルプログラムを書き込みます。アドレススペースは分離されているので、シェルプログラムの状態は常に明確に定義されています。