_set_new_handler
new
演算子がメモリの割り当てに失敗した場合は、独自のエラー処理機構に制御を移します。 Microsoft C++ コンパイラは、この関数を使用して標準ライブラリに std::set_new_handler
を実装します。
構文
_PNH _set_new_handler( _PNH pNewHandler );
パラメーター
pNewHandler
アプリケーションによって提供されたメモリ処理関数へのポインター。 引数 0 または nullptr
を指定すると、新しいハンドラーが削除されます。
戻り値
_set_new_handler
によって登録された前の例外処理関数へのポインターを返し、前の関数を後で復元できるようにします。 前の関数が設定されていない場合は、戻り値を使用して既定の動作を復元できます。 この値は、 nullptr
または 0 にすることができます。
解説
C++ の _set_new_handler
関数は、new
演算子がメモリの割り当てに失敗した場合に制御を取得する例外処理関数を指定します。 new
が失敗した場合、ランタイム システムは _set_new_handler
への引数として渡された例外処理関数を自動的に呼び出します。 _PNH
<new.h>
で定義されている、型int
を返し、size_t
型の引数を受け取る関数へのポインターです。 size_t
を使用して、割り当てられる領域の量を指定します。
既定のハンドラーはありません。
_set_new_handler
は本質的に、ガベージ コレクション スキームです。 ランタイム システムは、関数がゼロ以外の値を返すたびに割り当てを再試行し、関数がゼロを返すと失敗します。
プログラム内に _set_new_handler
関数が出現すると、引数リストに指定されている例外処理関数がランタイム システムに登録されます。
// _set_new_handler1.cpp
#include <new.h>
int handle_program_memory_depletion( size_t )
{
// Your code
}
int main( void )
{
_set_new_handler( handle_program_memory_depletion );
int *pi = new int[BIG_NUMBER];
}
既定では、 _set_new_handler
関数のグローバル状態はアプリケーションにスコープが設定されます。 これを変更するには、「CRT でのグローバル状態」を参照してください。
最後に _set_new_handler
関数に渡された関数のアドレスを保存して、後で再開することができます。
_PNH old_handler = _set_new_handler( my_handler );
// Code that requires my_handler
// . . .
_set_new_handler( old_handler )
// Code that requires old_handler
// . . .
C++ の _set_new_mode
関数では、malloc
の新しいハンドラー モードを設定します。 新しいハンドラー モードは、エラーが発生したときに、malloc
が _set_new_handler
によって設定された新しいハンドラー ルーチンを呼び出すかどうかを指定します。 malloc
では、既定で、メモリの割り当てエラーの際に新しいハンドラー ルーチンを呼び出しません。 この既定の動作をオーバーライドすると、malloc
がメモリの割り当てに失敗したときに、malloc
演算子が同じ理由で失敗したときと同じ方法で、new
によって新しいハンドラー ルーチンを呼び出すことができます。 既定値をオーバーライドするには、プログラムの早い段階で _set_new_mode(1);
を呼び出すか、 newmode.obj
にリンクします。
ユーザー定義の operator new
が指定されている場合、障害発生時に新しいハンドラー関数が自動的に呼び出されることはありません。
詳細については、「C++ 言語リファレンス」のnew
とdelete
を参照してください。
動的にリンクされたすべての DLL または実行可能ファイルに対して 1 つの _set_new_handler
ハンドラーが 1 つのプロセスに存在します。 _set_new_handler
を呼び出しても、ハンドラーが別のハンドラーに置き換えられる可能性があります。 または、新しいハンドラーは、プロセス内の別の DLL または実行可能ファイルによって設定されたハンドラーを置き換えることができます。
要件
機能 | 必須ヘッダー |
---|---|
_set_new_handler |
<new.h> |
互換性の詳細については、「 Compatibility」を参照してください。
例
この例では、割り当てが失敗すると、制御が MyNewHandler
に転送されます。 MyNewHandler
に渡される引数は、要求されたバイト数です。 MyNewHandler
から返される値は、割り当てを再試行するかどうかを示すフラグです。0 以外の値は、割り当てを再試行する必要があることを示し、0 の値は割り当てが失敗したことを示します。
// crt_set_new_handler.cpp
// Build for x86.
// WARNING: This code intentionally allocates memory until an allocation fails.
// Running this code can cause your system to become non-responsive.
#include <iostream>
#include <new>
#include <new.h>
static const int Big_number = 0x03FFFFFF;
struct MemoryHog {
int pork[Big_number];
};
class MemoryReserve {
MemoryHog* reserved = nullptr;
public:
MemoryReserve() {
reserved = new MemoryHog();
}
~MemoryReserve() noexcept {
if (reserved != nullptr)
delete reserved;
}
bool free_reserve() noexcept {
if (reserved != nullptr) {
delete reserved;
reserved = nullptr;
return true; // return true if memory freed
}
return false; // reserved memory exhausted.
}
};
// Global singleton for a MemoryReserve object
static MemoryReserve reserve{};
// Define a function to be called if new fails to allocate memory.
int MyNewHandler(size_t /* unused */)
{
// Call a function to recover some heap space. Return 1 on success.
if (reserve.free_reserve()) {
std::cerr << "MyNewHandler: Released reserved memory.\n";
return 1;
}
std::cerr << "MyNewHandler: Reserved memory exhausted.\n";
return 0;
}
static const int max_depth = 16; // recursion depth limiter
static int depth = 0;
void RecurseAlloc() {
MemoryHog* piggy = new MemoryHog{};
if (++depth < max_depth) // Recurse until memory exhausted or max_depth
RecurseAlloc();
depth--;
delete piggy;
return;
}
int main()
{
try {
_set_new_handler(MyNewHandler); // Set handler for new.
RecurseAlloc();
}
catch (std::bad_alloc& ex) {
std::cerr << "bad_alloc caught: " << ex.what() << '\n';
}
}
/* Output:
MyNewHandler: Released reserved memory.
MyNewHandler: Reserved memory exhausted.
bad_alloc caught: bad allocation
*/