Consider the following example:
#include <iostream>
#include <vector>
#include <new>
int main()
{
std::vector<int>::size_type n;
std::cout << "Enter array size: ";
std::cin >> n;
try
{
std::vector<int> v(n);
std::cout << "Allocation worked!\n";
}
catch (const std::bad_alloc& e)
{
std::cerr << "Allocation failed: " << e.what() << "\n";
}
}
If I use input 10'000'000'000
it throws std::bad_alloc
, as it should:
Enter array size: 10000000000
Allocation failed: std::bad_alloc
But if I use 18'446'744'073'709'551'615
(which is the maximum 64-bit value), it throws std::length_error
, which is not a bad_alloc
and thus crashes:
Enter array size: 18446744073709551615
terminate called after throwing an instance of 'std::length_error'
what(): cannot create std::vector larger than max_size()
I do understand that std::vector
has a max_size()
member which is supposed to tell me the maximum number of elements the container can hold due to implementation limits (rather than runtime memory limits). But it's not specified anywhere that if I exceed this size, it should throw std::length_error
instead of std::bad_alloc
. The only std::vector
member which should do this is reserve
, but I am not calling it.
I expected the code to throw std::bad_array_new_length
, because std::numeric_limits<std::size_t>::max() / sizeof(T) < n
. This would work well here, because std::bad_array_new_length
is derived from std::bad_alloc
and thus it would be caught.
How should I correctly handle the allocation error? One easy way out is to just catch std::exception
, but this means that I can't filter other exceptions if I want to. On the other hand, I don't know when I should be prepared for a std::length_error
, since it's not mentioned anywhere. Does the standard specify exactly which exceptions are allowed to be thrown by a certain function? Can I see this list anywhere?
You already got the answer
terminate called after throwing an instance of 'std::length_error'
what(): cannot create std::vector larger than max_size()
The exception is thrown because 18'446'744'073'709'551'615
is greater than std::vector<T>::max_size()
.
This is an implementation specific limitation. The distance between two pointers (begin()
i.e. &front()
and end()
i.e. after &back()
) can't be 18'446'744'073'709'551'615
, otherwise begin()
and end()
after overflow would point the same location.
Also take sizeof(T)
into account. It's obvious that 18'446'744'073'709'551'615 * sizeof(T)
can't fit into the 64-bit memory.
Also take into account that actual x86_64 CPUs can address only with 48 meaningful bits.
vector#capacity-5
Throws:
length_error
ifn > max_size()
.
length.error#1
The class
length_error
defines the type of objects thrown as exceptions to report an attempt to produce an object whose length exceeds its maximum allowable size.
container.reqmts#57
c.max_size()
Returns:distance(begin(), end())
for the largest possible container.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With