_set_new_handler
Trasferisce il controllo al meccanismo di gestione degli errori se l'operatore new
non riesce ad allocare la memoria. Il compilatore Microsoft C++ usa questa funzione per implementare std::set_new_handler
nella libreria standard.
Sintassi
_PNH _set_new_handler( _PNH pNewHandler );
Parametri
pNewHandler
Puntatore alla funzione di gestione della memoria fornita dall'applicazione. Un argomento pari a 0 o nullptr
fa sì che il nuovo gestore venga rimosso.
Valore restituito
Restituisce un puntatore alla funzione di gestione delle eccezioni precedente registrata da _set_new_handler
, in modo che la funzione precedente possa essere ripristinata in un secondo momento. Se non è stata impostata alcuna funzione precedente, è possibile usare il valore restituito per ripristinare il comportamento predefinito. Questo valore può essere nullptr
o 0.
Osservazioni:
La funzione C++ _set_new_handler
viene usata per specificare una funzione di gestione delle eccezioni che deve assumere il controllo se l'operatore new
non riesce ad allocare memoria. Se new
ha esito negativo, il sistema di runtime chiama automaticamente la funzione di gestione delle eccezioni passata come argomento di _set_new_handler
. _PNH
, definito in <new.h>
, è un puntatore a una funzione che restituisce il tipo int
e accetta un argomento di tipo size_t
. Usare size_t
per specificare la quantità di spazio da allocare.
Non esiste alcun gestore predefinito.
_set_new_handler
è fondamentalmente uno schema di garbage collection. Il sistema di runtime ritenta l'allocazione ogni volta che la funzione restituisce un valore diverso da zero e non riesce se la funzione restituisce 0.
Un'occorrenza della funzione _set_new_handler
in un programma registra la funzione di gestione delle eccezioni specificata nell'elenco di argomenti con il sistema di runtime:
// _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];
}
Per impostazione predefinita, lo _set_new_handler
stato globale della funzione è limitato all'applicazione. Per modificarlo, vedere Stato globale in CRT.
È possibile salvare l'indirizzo dell'ultima funzione passata alla funzione _set_new_handler
e crearne un'altra istanza in seguito:
_PNH old_handler = _set_new_handler( my_handler );
// Code that requires my_handler
// . . .
_set_new_handler( old_handler )
// Code that requires old_handler
// . . .
La funzione C++ _set_new_mode
imposta la nuova modalità del gestore per malloc
. La nuova modalità del gestore indica se, in caso di errore, malloc
deve chiamare la routine del nuovo gestore come impostato da _set_new_handler
. Per impostazione predefinita, malloc
non chiama la nuova routine del gestore in caso di errore di allocazione della memoria. È possibile eseguire l'override di questo comportamento predefinito in modo che, quando malloc
non riesce ad allocare memoria, malloc
chiami la routine del nuovo gestore, come fa l'operatore new
quando non riesce per lo stesso motivo. Per eseguire l'override dell'impostazione predefinita, chiamare _set_new_mode(1);
all'inizio del programma o collegare con newmode.obj
.
Se viene specificato un oggetto definito dall'utente operator new
, le nuove funzioni del gestore non vengono chiamate automaticamente in caso di errore.
Per altre informazioni, vedere new
e delete
nella Guida di riferimento al linguaggio C++.
Esiste un singolo _set_new_handler
gestore per tutte le DLL collegate dinamicamente o i file eseguibili in un singolo processo. Anche se si chiama _set_new_handler
, il gestore potrebbe essere sostituito da un altro. In alternativa, il nuovo gestore può sostituire un gestore impostato da un'altra DLL o eseguibile nel processo.
Requisiti
Funzione | Intestazione obbligatoria |
---|---|
_set_new_handler |
<new.h> |
Per altre informazioni sulla compatibilità, vedere Compatibility (Compatibilità).
Esempio
In questo esempio, quando l'allocazione non riesce, il controllo viene trasferito a MyNewHandler
. L'argomento passato a MyNewHandler
è il numero di byte richiesti. Il valore restituito da è un flag che indica se l'allocazione deve essere ritentata: un valore diverso da MyNewHandler
zero indica che l'allocazione deve essere ritentata e un valore zero indica che l'allocazione non è riuscita.
// 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
*/