Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

New throws bad_alloc despite <new> header not being defined?

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, and operator delete[]. [ Note: The implicit declarations do not introduce the names std, 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 to std or std::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?

like image 459
SergeantPenguin Avatar asked Jan 19 '16 15:01

SergeantPenguin


3 Answers

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.

like image 78
Andre Kostur Avatar answered Oct 22 '22 17:10

Andre Kostur


The name std::size_t is just a typedef for some other integer type, perhaps unsigned long or unsigned long long. The compiler knows the real parameter type for new, even if the name size_t isn't visible.

Similar for bad_alloc. The runtime code throwing a bad_alloc surely includes the <new> header, even if your program does not.

like image 31
Bo Persson Avatar answered Oct 22 '22 17:10

Bo Persson


A C++ standard header is allowed to include any other C++ header. Therefore you can get implementation-dependent access to std::bad_alloc without including <new>, and to std::size_t with including <cstddef> et al. I'm too lazy to look it up in your edition of the standard, but in the N4296 draft it's in §17.6.5.2:

A C++ header may include other C++ headers.

You can try this with a compiler.

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

Now let's 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
}
like image 23
Christian Hackl Avatar answered Oct 22 '22 16:10

Christian Hackl