2012-01-14 15 views
7

私は、このクラスがそれに仕事をするだろうと思いますが、私はこれで合計完璧に到達するためにどのような方法を見つけることだ。この二つのクラスC++、正しくコピーする方法std :: vector <Class *>コピーコンストラクタで?

// This is generic data structure containing some binary data 
class A { 
public: 
    A(); 
    A(const A&); 
    ~A(); 
} 

// Main data container 
class B { 
public: 
    B(); 
    B(const B&); 
    ~B(); 
protected: 
    std::vector<A *> data; 
} 

// Copy constructor for class b 
B::B(const B& orig):data() { 
    for(std::vector<A *>::const_iterator it = orig.data.begin(); 
     it < orig.data.end(); ++it){ 
     data.push_back(new A(*(*it))); 
    } 
} 

を使用しています。最初:data()

- この初期化が正しく空のベクターを初期化するのに必要な(そしてそれが良いとクリーンなコードを書くの一部ですか)?

コピーコンストラクタでvector::iteratorを使用する方法は、私が見つけた唯一の方法は、コードに書き込んだものです(constはコピーコンストラクタに必須です)。

コピーだけベクトルは単なるポインタ値と全体ではなく、オブジェクトをコピーするのでしょうか?

最後に、新しいデータの初期化...ループ全体を小さなコードで置き換える方法はありますか?オブジェクトのポインタを含むstd :: containersのコピーコンストラクタを書く方法はありますか?

サブ質問:私は(、パワーは()...オブジェクトをコピーするかどうかを決定するたびにコピーしない)vector<A *>がはるかに適切かつ効果的なだけでvector<A>より様々な理由で使用したと仮定してい

+0

「サブ質問:ポインタのベクトルを使用していると仮定していますか?" –

+0

イニシャライザのリストに' data'をあらかじめ割り当てておいてください。そういうふうにpush_back()を使うのは非常に効果がありません – lapk

+0

副答え:ポインタを使わないと使えないのですか? – Lol4t0

答えて

9

ザ・data()は、コンストラクタが入力される前にベクトルに自動的に行われるため、不要です。デフォルトコンストラクタ(または参照、定数など)を持たないPOD型または型であるメンバを初期化するだけで済みます。

ベクトルはそれが大きくなるにつれて、それ自体のサイズを変更する必要がないように、あなたは、もう一つは持っている要素の数とベクトルを初期化することができます。あなたがそれをしないと、小さなベクトルから始め、割り振りと再割り当てを使ってインクリメンタルに宛先サイズに到達します。これは非常に最初からベクトル正しいサイズになります:あなたは、それ以上push_backを使用していない

B::B(const B& orig) : data(orig.data.size()) { 
    for (std::size_t i = 0; i < orig.data.size(); ++i) 
     data[i] = new A(*orig.data[i]); 
} 

お知らせベクトルはすでにデフォルトが構築されている要素のorig.data.size()数がいっぱいですので、(中NULLありますポインタの場合)。あなたはイテレータの代わりに、それを反復するために整数を使用することができますので、

また、これは、コードをダウントリム。

あなたが本当にイテレータを使用する場合は、

B::B(const B& orig) : data(orig.data.size()) { 
    // auto is preferable here but I don't know if your compiler supports it 
    vector<A*>::iterator thisit = data.begin(); 
    vector<A*>::const_iterator thatit = orig.data.cbegin(); 

    for (; thatit != orig.data.cend(); ++thisit, ++thatit) 
     *thisit = new A(**thatit); 
} 

この利点を行うことができますが、それはしかし、の(ちょうどイテレータの種類を変更することにより、他のコンテナタイプ(listをのような)で動作することですあなたがautoを持っていればコースはなくなります)。

あなたは例外安全性を追加したい場合は、try/catchブロックが必要ですnew呼び出しの1つが例外をスローした場合は、メモリリークを持っていません

B::B(const B& orig) : data(orig.data.size()) { 
    try { 
     // auto is preferable here but I don't know if your compiler supports it 
     vector<A*>::iterator thisit = data.begin(); 
     vector<A*>::const_iterator thatit = orig.data.cbegin(); 

     for (; thatit != orig.data.cend(); ++thisit, ++thatit) 
      *thisit = new A(**thatit); 
    } catch (...) { 
     for (vector<A*>::iterator i = data.begin(); i != data.end(); ++i) 
      if (!*i) 
       break; 
      else 
       delete *i; 

     throw; 
    } 
} 

この道を。もちろん、それをむしろやりたいのであれば、イテレータなしでtry/catchの方法を使うことができます。

+1

' origを逆参照する必要があります。 data [i] '。 – someguy

+0

@someguy whoops、あなたは正しいです。 –

+2

もう一つ考慮すべきことはエラー処理です。ループの途中で?おそらくプログラムは終了するでしょうが、メモリ不足エラーがコールスタックでさらに処理されると、メモリリークが発生します。 –

関連する問題