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
The direct answer is that you cannot do that: you cannot define the vector as const and then add members to it.
As others have pointed out, the new standard offers the array class, which is probably more suitable for what you are doing.
If you are interested in a fixed length, the most related method in vector you can be interested in is reserve()
, which will set the vector<>
to the size of the given parameter, making vector expansions unnecessary.
If you cannot use Std C++11, then you need to create a wrapper class that does not let you modify the vector. For example:
#include <vector>
#include <iostream>
#include <exception>
#include <stdexcept>
using namespace std;
template <typename T>
class FinalVector {
public:
FinalVector(unsigned int size)
{ v.reserve( size ); }
const T &at(unsigned int i) const
{ return v.at( i ); }
T &at(unsigned int i)
{ return v.at( i ); }
T &operator[](unsigned int i)
{ return at( i ); }
const T &operator[](unsigned int i) const
{ return at( i ); }
void push_back(const T &x);
size_t size() const
{ return v.size(); }
size_t capacity() const
{ return v.size(); }
private:
std::vector<T> v;
};
template<typename T>
void FinalVector<T>::push_back(const T &x)
{
if ( v.size() < v.capacity() ) {
v.push_back( x );
} else {
throw runtime_error( "vector size exceeded" );
}
}
int main()
{
FinalVector<int> v( 3 );
v.push_back( 1 );
v.push_back( 2 );
v.push_back( 3 );
for(size_t i = 0; i < v.size(); ++i) {
cout << v[ i ] << endl;
}
}
Hope this helps.
The actual error is because you declare the vector to be constant, meaning you can never change the contents.
Then when you try to get a non-constant reference to an entry in the vector, the compiler tells you that you can't do that, because then you could change the constant value stored in the vector.
As for creating a vector with a size that can be fixed at runtime, but not change size after the vector has been created, then you have to create a container adaptor. Basically you have to create a wrapper around another container, just like e.g. std::stack
does.
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