6

I have been told that it is good practice to call vector.reserve() before inserting a large amount of elements. I just came upon a situation where I want to put a large number of const elements into a vector. When calling reserve(), however, a compiler error is thrown.

Consider the following code reproducing the problem:

#include <vector>

int main()
{
    std::vector<const int> vec;
    vec.reserve(2);
}

This results in the following huge compiler error:

In file included from /usr/include/x86_64-linux-gnu/c++/4.8/bits/c++allocator.h:33:0,
                 from /usr/include/c++/4.8/bits/allocator.h:46,
                 from /usr/include/c++/4.8/vector:61,
                 from vecreserve.cpp:1:
/usr/include/c++/4.8/ext/new_allocator.h: In instantiation of ‘struct __gnu_cxx::new_allocator’:
/usr/include/c++/4.8/bits/allocator.h:92:11:   required from ‘class std::allocator’
/usr/include/c++/4.8/bits/alloc_traits.h:90:43:   required from ‘struct std::allocator_traits >’
/usr/include/c++/4.8/ext/alloc_traits.h:121:10:   required from ‘struct __gnu_cxx::__alloc_traits >’
/usr/include/c++/4.8/bits/stl_vector.h:75:28:   required from ‘struct std::_Vector_base >’
/usr/include/c++/4.8/bits/stl_vector.h:210:11:   required from ‘class std::vector’
vecreserve.cpp:5:26:   required from here
/usr/include/c++/4.8/ext/new_allocator.h:93:7: error: ‘const _Tp* __gnu_cxx::new_allocator::address(__gnu_cxx::new_allocator::const_reference) const [with _Tp = const int; __gnu_cxx::new_allocator::const_pointer = const int*; __gnu_cxx::new_allocator::const_reference = const int&]’ cannot be overloaded
       address(const_reference __x) const _GLIBCXX_NOEXCEPT
       ^
/usr/include/c++/4.8/ext/new_allocator.h:89:7: error: with ‘_Tp* __gnu_cxx::new_allocator::address(__gnu_cxx::new_allocator::reference) const [with _Tp = const int; __gnu_cxx::new_allocator::pointer = const int*; __gnu_cxx::new_allocator::reference = const int&]’
       address(reference __x) const _GLIBCXX_NOEXCEPT
       ^
/usr/include/c++/4.8/ext/new_allocator.h: In instantiation of ‘void __gnu_cxx::new_allocator::deallocate(__gnu_cxx::new_allocator::pointer, __gnu_cxx::new_allocator::size_type) [with _Tp = const int; __gnu_cxx::new_allocator::pointer = const int*; __gnu_cxx::new_allocator::size_type = long unsigned int]’:
/usr/include/c++/4.8/bits/stl_vector.h:174:4:   required from ‘void std::_Vector_base::_M_deallocate(std::_Vector_base::pointer, std::size_t) [with _Tp = const int; _Alloc = std::allocator; std::_Vector_base::pointer = const int*; std::size_t = long unsigned int]’
/usr/include/c++/4.8/bits/vector.tcc:80:28:   required from ‘void std::vector::reserve(std::vector::size_type) [with _Tp = const int; _Alloc = std::allocator; std::vector::size_type = long unsigned int]’
vecreserve.cpp:6:16:   required from here
/usr/include/c++/4.8/ext/new_allocator.h:110:30: error: invalid conversion from ‘const void*’ to ‘void*’ [-fpermissive]
       { ::operator delete(__p); }
                              ^
In file included from /usr/include/c++/4.8/ext/new_allocator.h:33:0,
                 from /usr/include/x86_64-linux-gnu/c++/4.8/bits/c++allocator.h:33,
                 from /usr/include/c++/4.8/bits/allocator.h:46,
                 from /usr/include/c++/4.8/vector:61,
                 from vecreserve.cpp:1:
/usr/include/c++/4.8/new:95:6: error:   initializing argument 1 of ‘void operator delete(void*)’ [-fpermissive]
 void operator delete(void*) _GLIBCXX_USE_NOEXCEPT
      ^
In file included from /usr/include/c++/4.8/vector:60:0,
                 from vecreserve.cpp:1:
/usr/include/c++/4.8/bits/stl_algobase.h: In instantiation of ‘_OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = true; _II = const int*; _OI = const int*]’:
/usr/include/c++/4.8/bits/stl_algobase.h:428:38:   required from ‘_OI std::__copy_move_a2(_II, _II, _OI) [with bool _IsMove = true; _II = const int*; _OI = const int*]’
/usr/include/c++/4.8/bits/stl_algobase.h:460:17:   required from ‘_OI std::copy(_II, _II, _OI) [with _II = std::move_iterator; _OI = const int*]’
/usr/include/c++/4.8/bits/stl_uninitialized.h:93:53:   required from ‘static _ForwardIterator std::__uninitialized_copy::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator; _ForwardIterator = const int*]’
/usr/include/c++/4.8/bits/stl_uninitialized.h:117:41:   required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator; _ForwardIterator = const int*]’
/usr/include/c++/4.8/bits/stl_uninitialized.h:258:63:   required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator&) [with _InputIterator = std::move_iterator; _ForwardIterator = const int*; _Tp = const int]’
/usr/include/c++/4.8/bits/stl_vector.h:1142:29:   required from ‘std::vector::pointer std::vector::_M_allocate_and_copy(std::vector::size_type, _ForwardIterator, _ForwardIterator) [with _ForwardIterator = std::move_iterator; _Tp = const int; _Alloc = std::allocator; std::vector::pointer = const int*; std::vector::size_type = long unsigned int]’
/usr/include/c++/4.8/bits/vector.tcc:75:70:   required from ‘void std::vector::reserve(std::vector::size_type) [with _Tp = const int; _Alloc = std::allocator; std::vector::size_type = long unsigned int]’
vecreserve.cpp:6:16:   required from here
/usr/include/c++/4.8/bits/stl_algobase.h:390:70: error: no matching function for call to ‘std::__copy_move::__copy_m(const int*&, const int*&, const int*&)’
                        _Category>::__copy_m(__first, __last, __result);
                                                                      ^
/usr/include/c++/4.8/bits/stl_algobase.h:390:70: note: candidate is:
/usr/include/c++/4.8/bits/stl_algobase.h:368:9: note: template static _Tp* std::__copy_move::__copy_m(const _Tp*, const _Tp*, _Tp*) [with _Tp = _Tp; bool _IsMove = true]
         __copy_m(const _Tp* __first, const _Tp* __last, _Tp* __result)
         ^
/usr/include/c++/4.8/bits/stl_algobase.h:368:9: note:   template argument deduction/substitution failed:
/usr/include/c++/4.8/bits/stl_algobase.h:390:70: note:   deduced conflicting types for parameter ‘_Tp’ (‘int’ and ‘const int’)
                        _Category>::__copy_m(__first, __last, __result);
                                                                      ^

Why does this happen? Should I not call reserve on a vector of const elements? If so, why not?

Chris
  • 6,914
  • 5
  • 54
  • 80
  • 1
    It's because of your `const int` – P0W Sep 06 '13 at 07:30
  • @P0W I know, can you please be more specific? Why can I not call `reserve` on a `vector` of `const int`? – Chris Sep 06 '13 at 07:31
  • 7
    Because when you call reserve() it'll allocate space for them but then you won't be able to modify them later (because they're const...) so they'll **always have the default value** assigned by reserve(). That said for this very special issue I would cast const away (because it'll affect only compiler checks, not generated code). – Adriano Repetti Sep 06 '13 at 07:33

2 Answers2

10

You are violating the requirements for the elements stated by the class vector. An element must be CopyAssignable.

3

const int is not a valid type to put into any standard container since it is not assignable.

P0W
  • 46,614
  • 9
  • 72
  • 119