New throws bad_alloc even though the <new> header is undefined?
How is it that the new expression in the program can cause a bad_alloc error, despite the absence of #include <new> (since this error is defined in the <new> header )?
From 3.7.4. from N3337:
The library provides default definitions for global distribution and release functions. Some global distribution and release functions are interchangeable (18.6.1). A C ++ program should provide no more than one definition of a plugin allocation or release function. Any such definition of a function replaces the default version provided in the library (17.6.4.6). The following distribution and release functions (18.6) are implicitly declared in the global scope in each translation unit of the program.
void* operator new(std::size_t); void* operator new[](std::size_t); void operator delete(void*); void operator delete[](void*);These implicit declarations only enter the function names
operator new,operator new[],operator deleteandoperator delete[]. [ Note. Implicit declarations do not enter the namesstd,std::size_tor any other names that the library uses to declare these names. Thus, a new expression, delete-expression, or a function call that refers to one of these functions without including the<new>header, is well formed. However, referring tostdorstd::size_tis poorly formed if the name has not been declared by including the corresponding header. -end note ] Distribution and / or release functions can also be declared and defined for any class.
This is still not clear to me. Implicit declarations use std::size_t but do not enter them (and the same should be the case with bad_alloc )? And std::size_t does not need to be entered before the new expression. Can I understand how this happens, or do I need to take it at face value?
Your quote says that these global functions exist and are implicitly declared as described. Thus, when calling new , the global function in the standard library is called. The implementation of the global new function is to throw std::bad_alloc , and this implementation had access to <new> at compile time, so it knows how to throw std::bad_alloc . Your code should not know what std::bad_alloc is unless you catch it. But, in addition to catching it, it looks like you are calling some other function from some other library, which may cause some arbitrary exception. You do not need to know the details of this exception unless you are trying to catch it, but that does not stop the caller from calling it.
The name std::size_t is just a typedef for some other integer type, possibly unsigned long or unsigned long long . The compiler knows the actual parameter type for new , even if the name size_t not displayed.
Similarly for bad_alloc . The execution code casting bad_alloc certainly includes the <new> header, even if your program does not work.
A standard C ++ header can include any other C ++ header. Therefore, you can get implementation-specific access to std::bad_alloc without including <new> and std::size_t with <cstddef> et al. I'm too lazy to see this in your edition of the standard, but in project N4296 in section 17.6.5.2:
The C ++ header may contain other C ++ headers.
You can try this with the compiler.
int main() { std::size_t x; // error std::bad_alloc y; // error } Now add a completely unrelated #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 }