Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does std::vector constructor throw std::length_error instead of std::bad_alloc?

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?

like image 358
DarkAtom Avatar asked Oct 16 '25 00:10

DarkAtom


1 Answers

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 if n > 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.

like image 193
273K Avatar answered Oct 17 '25 15:10

273K