How is it that a new
expression in a program can throw a bad_alloc
error despite there being no #include <new>
(since this error is defined in the <new>
header)?
From 3.7.4. of N3337:
The library provides default definitions for the global allocation and deallocation functions. Some global allocation and deallocation functions are replaceable (18.6.1). A C++ program shall provide at most one definition of a replaceable allocation or deallocation function. Any such function definition replaces the default version provided in the library (17.6.4.6). The following allocation and deallocation functions (18.6) are implicitly declared in global scope in each translation unit of a program.
void* operator new(std::size_t); void* operator new[](std::size_t); void operator delete(void*); void operator delete[](void*);
These implicit declarations introduce only the function names
operator new
,operator new[]
,operator delete
, andoperator delete[]
. [ Note: The implicit declarations do not introduce the namesstd
,std::size_t
, or any other names that the library uses to declare these names. Thus, a new-expression, delete-expression or function call that refers to one of these functions without including the header<new>
is well-formed. However, referring tostd
orstd::size_t
is ill-formed unless the name has been declared by including the appropriate header. —end note ] Allocation and/or deallocation functions can also be declared and defined for any class
This still isn't clear to me. The implicit declarations use std::size_t
but do not introduce them (and the same must be the case for bad_alloc
)? And std::size_t
doesn't need to be introduced before a new
expression can be used? Can any sense be made of how this is, or do I have to take it at face value?
Your quote says that those global functions exist and are implicitly declared as described. Thus when you invoke new
, the global function in the standard library is called. The implementation of the global function new
is the one throwing std::bad_alloc
, and that implementation had access to <new>
at the time of compilation, thus knows how to throw an std::bad_alloc
. Your code doesn't need to know what a std::bad_alloc
is, unless you're trying to catch it. But other than catching it, this is like you calling any other function from some other library that may be throwing some arbitrary exception. You don't need to know about the details of that exception unless you're trying to catch it, but that doesn't stop the callee from being able to throw it.