13

C++ では、固定サイズ (ただし、サイズは実行時に決定されます) の std::vector を割り当ててから、この vector の要素に書き込みます。これは私が使用しているコードです:

int b = 30;
const std::vector<int> test(b);
int &a = test[3];

ただし、これによりコンパイラ (MSVC 2010 Pro) エラーが発生します。

エラー C2440: '初期化中': 'const int' から 'int &' に変換できません。コンバージョンは修飾子を失います。

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

したがって、 std::vector はコンテナーの const ネスをベクターの要素に伝播するように見えますが、要素を const にしたい場合は を使用していたので、これは奇妙に思えstd::vector<const int>ます。したがって、これは std::vector の欠点だと思います。

いずれにせよ、構築後にサイズを変更できないが、要素を書き込むことができる std::vector を作成するにはどうすればよいですか?

4

3 に答える 3

14

これは、独自のラッパー クラスを作成しない限り不可能です。プレーンな を使用する場合は、メンバ関数、またはを直接的または間接的に (たとえば a を介して)std::vector使用しないことで、自己規律に頼る必要があります。insert()push_back()emplace_back()back_inserter

新しい C++14 標準の動的配列の現在の提案があることに注意してください。

[...] 要素数が構築時にバインドされる配列の新しい機能を定義することを提案します。これらの動的配列を dynarray と呼びます。

この提案には、実際には、独自のコードで使用できる参照実装が付属しています (namespace 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
于 2013-04-05T11:12:05.377 に答える
2

直接的な答えは、それはできないということです。ベクトルを const として定義してから、それにメンバーを追加することはできません。

他の人が指摘したように、新しい標準は配列クラスを提供します。これはおそらくあなたがしていることにより適しています。

固定長に関心がある場合、関心のある vector の最も関連性の高いメソッドは です。これはreserve()、 をvector<>指定されたパラメータのサイズに設定し、vector の拡張を不要にします。

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;
    }
}

お役に立てれば。

于 2013-04-05T11:24:27.987 に答える