Create a fixed size std::vector and write to the elements
arrays, c++, constants, dynamic-arrays, stdvector
Solution
This is not possible without writing your own wrapper class. If you want to use a plain `std::vector`, you have to rely on self-discipline by not using the member functions `insert()`, `push_back()` or `emplace_back()`, either directly or indirectly (e.g. via a `back_inserter`).
Note that there is a current proposal for dynamic arrays for the new C++14 Standard:
[...] we propose to define a new facility for arrays where the number of elements is bound at construction. We call these dynamic arrays, dynarray.
The proposal actually comes with a reference implementation that you can use in your own code (make sure to change `namespace std` into something else for the time being).
namespace std {
template< class T >
struct dynarray
{
// types:
typedef T value_type;
typedef T& reference;
typedef const T& const_reference;
typedef T* iterator;
typedef const T* const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
// fields:
private:
T* store;
size_type count;
// helper functions:
void check(size_type n)
{ if ( n >= count ) throw out_of_range("dynarray"); }
T* alloc(size_type n)
{ if ( n > std::numeric_limits<size_type>::max()/sizeof(T) )
throw std::bad_array_length();
return reinterpret_cast<T*>( new char[ n*sizeof(T) ] ); }
public:
// construct and destruct:
dynarray() = delete;
const dynarray operator=(const dynarray&) = delete;
explicit dynarray(size_type c)
: store( alloc( c ) ), count( c )
{ size_type i;
try {
for ( size_type i = 0; i < count; ++i )
new (store+i) T;
} catch ( ... ) {
for ( ; i > 0; --i )
(store+(i-1))->~T();
throw;
} }
dynarray(const dynarray& d)
: store( alloc( d.count ) ), count( d.count )
{ try { uninitialized_copy( d.begin(), d.end(), begin() ); }
catch ( ... ) { delete store; throw; } }
~dynarray()
{ for ( size_type i = 0; i < count; ++i )
(store+i)->~T();
delete[] store; }
// iterators:
iterator begin() { return store; }
const_iterator begin() const { return store; }
const_iterator cbegin() const { return store; }
iterator end() { return store + count; }
const_iterator end() const { return store + count; }
const_iterator cend() const { return store + count; }
reverse_iterator rbegin()
{ return reverse_iterator(end()); }
const_reverse_iterator rbegin() const
{ return reverse_iterator(end()); }
reverse_iterator rend()
{ return reverse_iterator(begin()); }
const_reverse_iterator rend() const
{ return reverse_iterator(begin()); }
// capacity:
size_type size() const { return count; }
size_type max_size() const { return count; }
bool empty() const { return count == 0; }
// element access:
reference operator[](size_type n) { return store[n]; }
const_reference operator[](size_type n) const { return store[n]; }
reference front() { return store[0]; }
const_reference front() const { return store[0]; }
reference back() { return store[count-1]; }
const_reference back() const { return store[count-1]; }
const_reference at(size_type n) const { check(n); return store[n]; }
reference at(size_type n) { check(n); return store[n]; }
// data access:
T* data() { return store; }
const T* data() const { return store; }
};
} // namespace std
Problem
In C++ I wish to allocate a fixed-size (but size determined at runtime) std::vector then write to the elements in this vector. This is the code I am using: ``` int b = 30; const std::vector<int> test(b); int &a = test[3]; ``` However, this gives me a compiler (MSVC 2010 Pro) error: error C2440: 'initializing' : cannot convert from 'const int' to 'int &'. Conversion loses qualifiers. My understanding of const is that it makes all of the member variables of a class constant. For example, the following works fine: ``` class myvec { public: myvec(int num) : ptr_m(new int[num]) {}; ~myvec() { delete ptr_m; } void resize(int num) { delete ptr_m; ptr_m = new int[num]; } int & operator[] (int i) const { return ptr_m[i]; } int *ptr_m; }; const myvec test(30); int &a = test[3]; // This is fine, as desired test.resize(10); // Error here, as expected ``` It would therefore seem that std::vector propagates the const-ness of the container to the elements of the vector, which seems odd because if I had wanted the elements to be const I would have used `std::vector<const int>`. This therefore strikes me as a shortcoming of std::vector. In any case, how can I create a std::vector whose size cannot be changed after construction, but whose elements can be written to?