2016-10-14 5 views
0

私はほとんどstd :: vector型のベクタ(うまくいけば)の実装をやっていますが、コードに少しのバグがあり、どこから見つけることができません。基本的には、Vectorを構築してpush_backを使用すると、ベクトルは新しい要素(ベクトルの2倍の大きさ)を自動的に割り当てますが、余分な領域は0に初期化されます。ここで 新しいオブジェクトを割り当てるC++のベクタの実装

は私のコードです:

Vector.h

#include <memory> 
#include <cstddef> 

template <class T> 
class Vec{ 
    public: 
     typedef T* iterator; 
     typedef const T* const_iterator; 
     typedef size_t size_type; 
     typedef T value_type; 

     Vec(){create();} 
     Vec(size_type n, const T& val = T()) {create(n, val);} 

     ~Vec() {uncreate();} 

     //copy constructor 
     Vec(const Vec& v) {create(v.begin(), v.end());} 
     //assignment operator 
     Vec& operator=(const Vec&); 

     size_type size() const {return limit - data;} 

     //index operators 
     T& operator[](size_type i) {return data[i];} 
     const T& operator[](size_type i) const {return data[i];} 

     iterator begin() {return data;} 
     const_iterator begin() const {return data;} 

     iterator end() {return limit;} 
     const_iterator end() const {return limit;} 

     void push_back(const T&); 


    private: 
     iterator data; //1st element 
     iterator avail; //one past last constructed element 
     iterator limit; //one past last available element 

     //Memory management 
     std::allocator<T> alloc; 

     void create(); 
     void create(size_type, const T&); 
     void create(const_iterator, const_iterator); 

     void uncreate(); 

     void grow(); 
     void unchecked_append(const T&); 

}; 

template <class T> 
void Vec<T>::push_back(const T& val){ 
    if(avail == limit) 
     grow(); 
    unchecked_append(val); 
} 

template <class T> 
Vec<T>& Vec<T>::operator=(const Vec& rhs){ 
    //self-assign 
    if(&rhs != this){ 
     uncreate; 
     create(rhs.begin(), rhs.end()); 
    } 
    return *this; 
} 

// Empty Vector, pointers to 0 
template <class T> void Vec<T>::create(){ 
    data = avail = limit = 0; 
} 

// Allocate memory for (size) 
template <class T> void Vec<T>::create(size_type n, const T& val){ 
    data = alloc.allocate(n); // returns pointer to first element 
    limit = avail = data +n; 
    std::uninitialized_fill(data, limit, val); 
} 

template <class T> void Vec<T>::create(const_iterator i, const_iterator j){ 
    data = alloc.allocate(j-i); 
    limit = avail =std::uninitialized_copy(i, j, data); 
} 

template <class T> void Vec<T>::uncreate(){ 
    if(data){ 
     iterator it = avail; 
     while(it != data) 
      alloc.destroy(--it); 

     // Free space 
     alloc.deallocate(data, limit - data); 
    } 
    // Empty Vector 
    data = limit = avail = 0; 
} 

template <class T> void Vec<T>::grow(){ 
    // Allocate twice the space we had 
    size_type new_size = std::max(2 * (limit - data), ptrdiff_t(1)); 

    // Allocate new space and copy to new space 
    iterator new_data = alloc.allocate(new_size); 
    iterator new_avail = std::uninitialized_copy(data, avail, new_data); 

    // Return old space used 
    uncreate(); 

    // Reset pointers to point to new space 
    data = new_data; 
    avail = new_avail; 
    limit = data + new_size; 
} 

template <class T> void Vec<T>::unchecked_append(const T& val){ 
    alloc.construct(avail++, val); 
} 

そして、これは私が

main.cppに

#include "vector.h" 
#incude <iostream> 

using namespace std; 

int main(){ 
    Vec<int> v1; 
    v1.push_back(12); 
    v1.push_back(9); 
    v1.push_back(74); 
    v1.push_back(22); 
    Vec<int> v2 = v1; 
    v2.push_back(70); //After doing this the vector is (12, 9, 74, 22, 70, 0, 0, 0) 
    for(auto e: v2) cout << e << " "; 
    cout << endl; 
} 

おかげでベクトルを作成する方法であります任意のヘルプと実際のコードに対するフィードバックも高く評価されます。 :)

+2

あなたの 'std :: allocator'はいつもこれを行います、あなたはチェックしましたか?おそらく、デバッグビルドでそれを行うのでしょうか、これは1つですか?新しいデータが各ステップでどのように見えるかを見て、 'grow'メソッドを実行してみましたか? – Useless

+0

あなたのコメントはありません。どのようにv2に複数の要素がありますか?あなたは70を追加しただけですか?それとも70がv1で終わるのですか? – Borgleader

+0

タイプミスがあり、編集しました。それをv1から初期化します。 –

答えて

1

問題が

template <class T> void Vec<T>::grow(){ 
    // Allocate twice the space we had 
    size_type new_size = std::max(2 * (limit - data), ptrdiff_t(1)); 
.... 
.... 
} 

(それは本当に問題であれば、私は知りません)あなたの問題を再現するために、任意のベクターコピーを実行する必要はありません。

問題が5 elemnt

今サイズを印刷
v1.push_back(12); 
    v1.push_back(9); 
    v1.push_back(74); 
    v1.push_back(22); 
    v1.push_back(22); //5th elemnt. 

を挿入した後にも最初のベクトルで見ることができます。

cout<<v1.size()<<endl; - it says 8. 

stdベクトルでさえ、resize()の後では、空の要素にゼロを出力するのが通常の動作です。この例では

ルック:「:new_size」計算 http://en.cppreference.com/w/cpp/container/vector/resize

あなたは追加のゼロをしたくない場合は、あなたを微調整する必要があります。

+0

はい。私はそのnew_size計算を行うことを意味しました。私のエラーは、クラスから間違った変数を渡すだけでした。私は "avail"ではなく "limit"を渡していました。制限は、配列全体(割り当てられたメモリを含む)の終わりを過ぎて1つです。 Availは、最後の初期化された値の最後を過ぎて1つです。 –

+0

あります。良い。 – Naidu

関連する問題