2016-01-19 5 views
5

Come è possibile che un'espressione new in un programma possa generare un errore bad_alloc nonostante non ci sia #include <new> (poiché questo errore è is defined in the <new> header)?Nuovi tiri bad_alloc nonostante l'intestazione <new> non sia stata definita?

Da 3.7.4. di N3337:

La libreria fornisce le definizioni predefinite per le funzioni di allocazione e deallocazione globali. Alcune funzioni di assegnazione e deallocazione globali sono sostituibili (18.6.1). Un programma C++ deve fornire al massimo una definizione di una funzione di allocazione o di deallocazione sostituibile. Qualsiasi definizione di tale funzione sostituisce la versione predefinita fornita nella libreria (17.6.4.6). Le seguenti funzioni di allocazione e deallocazione (18.6) sono implicitamente dichiarate nell'ambito globale in ciascuna unità di traduzione di un programma.

void* operator new(std::size_t); 

void* operator new[](std::size_t); 

void operator delete(void*); 

void operator delete[](void*); 

Queste dichiarazioni implicite introdurre solo i nomi delle funzioni operator new, operator new[], operator delete e operator delete[]. [Nota: le dichiarazioni implicite non introducono i nomi std, std::size_t o altri nomi utilizzati dalla libreria per dichiarare questi nomi. Pertanto, una nuova espressione, delete-expression o chiamata di funzione che fa riferimento a una di queste funzioni senza includere l'intestazione <new> è ben formata. Tuttavia, il riferimento a std o std::size_t non è corretto a meno che il nome non sia stato dichiarato includendo l'intestazione appropriata. -end notare] Assegnazione e/o funzioni di deallocazione possono anche essere dichiarati e definiti per ogni classe

Questo ancora non mi è chiaro. Le dichiarazioni implicite utilizzano std::size_t ma non le introducono (e lo stesso deve essere il caso per bad_alloc)? E non è necessario introdurre std::size_t prima che sia possibile utilizzare un'espressione new? Può esserci qualche senso su come sia, o devo prenderlo al valore nominale?

+1

Bene, si sta collegando con la libreria standard C++, che include '', e quindi conosce 'std :: bad_alloc'. –

+0

Potrebbe avere qualcosa a che fare con il fatto che un'intestazione standard C++ è ufficialmente autorizzata a includere qualsiasi altra intestazione standard C++, ma suppongo che non sia tutta la storia per quanto riguarda queste funzioni. –

+0

Dopo alcuni esperimenti, concludo che questo è effettivamente il caso. Scriverò una risposta a riguardo. –

risposta

4

il tuo preventivo dice che queste funzioni globali esistono e sono implicitamente dichiarate come descritto. Pertanto, quando invochi new, viene chiamata la funzione globale nella libreria standard. L'implementazione della funzione globale new è quella che lancia std::bad_alloc e che l'implementazione ha avuto accesso a <new> al momento della compilazione, quindi sa come lanciare un std::bad_alloc. Il tuo codice non ha bisogno di sapere cos'è un std::bad_alloc, a meno che tu non stia cercando di prenderlo. Ma a parte prenderlo, è come se chiamassi qualsiasi altra funzione da qualche altra libreria che potrebbe lanciare qualche eccezione arbitraria. Non è necessario conoscere i dettagli di tale eccezione, a meno che non si stia cercando di catturarlo, ma ciò non impedisce al destinatario di essere in grado di lanciarlo.

+0

Ho pensato che qualsiasi cosa che un programma usa che proviene dalla libreria standard deve avere un'intestazione '# include'? Quindi esiste un accesso implicito alla libreria standard per trovare queste definizioni delle funzioni 'new' e' delete'? Anche un programma minimo come 'main() {}' ha ancora bisogno di accedere alla libreria standard? – SergeantPenguin

+0

@SergeantPenguin Per ottenere un po 'più nitpicky, quando dici 'new', non stai invocando direttamente la libreria standard. 'new' è una cosa del linguaggio. In qualche punto lungo la linea di esecuzione del 'new', il linguaggio causerà una chiamata a una funzione di allocazione globale per ottenere la memoria effettiva in cui risiederà l'oggetto (probabilmente a breve seguito dalla lingua che richiama il costruttore dell'oggetto in quella memoria) . La libreria standard fornisce una funzione di allocazione globale predefinita (con la firma della funzione specificata in modo che il linker possa trovarla) in modo che non sia necessario scriverne una da soli. –

4

Il nome std::size_t è solo un typedef per qualche altro tipo intero, forse unsigned long o unsigned long long. Il compilatore conosce il tipo di parametro reale per new, anche se il nome size_t non è visibile.

Simile per bad_alloc. Il codice runtime che genera un bad_alloc include sicuramente l'intestazione <new>, anche se il programma non lo fa.

3

Un'intestazione standard C++ può includere qualsiasi altra intestazione C++. Pertanto è possibile ottenere l'accesso dipendente dall'implementazione a std::bad_alloc senza includere <new> e a std::size_t includendo <cstddef> e al. Sono troppo pigro per cercarlo nella tua edizione dello standard, ma nella bozza N4296 è in §17.6.5.2:

Un'intestazione C++ può includere altre intestazioni C++.

Si può provare con un compilatore.

int main() 
{ 
    std::size_t x; // error 
    std::bad_alloc y; // error 
} 

Ora aggiungiamo un completamente estranei #include:

#include <complex> 

int main() 
{ 
    std::size_t x; // probably not an error anymore, depends on compiler 
    std::bad_alloc y; // probably not an error anymore, depends on compiler 
} 
Problemi correlati