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:
在c++中,我希望分配一个固定大小(但是在运行时确定大小)的std:::vector然后写入这个向量中的元素。这是我正在使用的代码:
int b = 30;
const std::vector<int> test(b);
int &a = test[3];
However, this gives me a compiler (MSVC 2010 Pro) error:
但是,这给了我一个编译器(MSVC 2010 Pro)错误:
error C2440: 'initializing' : cannot convert from 'const int' to 'int &'. Conversion loses qualifiers.
错误C2440:“初始化”:不能从“const int”转换为“int &”。转换损失限定符。
My understanding of const is that it makes all of the member variables of a class constant. For example, the following works fine:
我对const的理解是它使类的所有成员变量都成为常量。例如,以下方法很有效:
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.
因此,std::向量将容器的完整性传播到向量的元素上,这看起来很奇怪,因为如果我想让元素成为常量,我就会使用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?
无论如何,我如何创建一个std::vector,它的大小在构造之后不能更改,但是它的元素可以被写入?
3 个解决方案
#1
12
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
).
如果不编写自己的包装类,这是不可能的。如果您想使用一个普通的std::vector,您必须依赖于自律,不使用成员函数insert()、push_back()或emplace_back(),直接或间接地(例如通过back_inserter)。
Note that there is a current proposal for dynamic arrays for the new C++14 Standard:
注意,对于新的c++ 14标准,目前有一个动态数组的建议:
[...] we propose to define a new facility for arrays where the number of elements is bound at construction. We call these dynamic arrays, dynarray.
[…[参考译文]我们提议为数组定义一种新的工具,在这种工具中元素的数量在构造时受到限制。我们称之为动态数组,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).
该建议实际上附带了一个参考实现,您可以在自己的代码中使用它(确保将名称空间std更改为当前的其他内容)。
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
#2
1
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.
对于创建一个在运行时可以固定大小的向量,但是在创建向量之后不会改变大小,那么您必须创建一个容器适配器。基本上,您必须围绕另一个容器创建一个包装器,就像std: stack那样。
#3
1
The direct answer is that you cannot do that: you cannot define the vector as const and then add members to it.
直接的答案是不能这样做:不能将向量定义为const,然后添加成员。
As others have pointed out, the new standard offers the array class, which is probably more suitable for what you are doing.
正如其他人指出的,新标准提供了array类,它可能更适合您正在做的工作。
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.
如果您对固定长度感兴趣,那么您可能感兴趣的向量中最相关的方法是reserve(),它会将向量<>设置为给定参数的大小,使向量展开变得不必要。
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:
如果不能使用Std c++ 11,那么需要创建一个不允许修改向量的包装器类。例如:
#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.
希望这个有帮助。
#1
12
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
).
如果不编写自己的包装类,这是不可能的。如果您想使用一个普通的std::vector,您必须依赖于自律,不使用成员函数insert()、push_back()或emplace_back(),直接或间接地(例如通过back_inserter)。
Note that there is a current proposal for dynamic arrays for the new C++14 Standard:
注意,对于新的c++ 14标准,目前有一个动态数组的建议:
[...] we propose to define a new facility for arrays where the number of elements is bound at construction. We call these dynamic arrays, dynarray.
[…[参考译文]我们提议为数组定义一种新的工具,在这种工具中元素的数量在构造时受到限制。我们称之为动态数组,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).
该建议实际上附带了一个参考实现,您可以在自己的代码中使用它(确保将名称空间std更改为当前的其他内容)。
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
#2
1
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.
对于创建一个在运行时可以固定大小的向量,但是在创建向量之后不会改变大小,那么您必须创建一个容器适配器。基本上,您必须围绕另一个容器创建一个包装器,就像std: stack那样。
#3
1
The direct answer is that you cannot do that: you cannot define the vector as const and then add members to it.
直接的答案是不能这样做:不能将向量定义为const,然后添加成员。
As others have pointed out, the new standard offers the array class, which is probably more suitable for what you are doing.
正如其他人指出的,新标准提供了array类,它可能更适合您正在做的工作。
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.
如果您对固定长度感兴趣,那么您可能感兴趣的向量中最相关的方法是reserve(),它会将向量<>设置为给定参数的大小,使向量展开变得不必要。
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:
如果不能使用Std c++ 11,那么需要创建一个不允许修改向量的包装器类。例如:
#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.
希望这个有帮助。