4

私は非常に新しいプログラマーで超初心者なので、C++ についてあまり知りません。特に、ポインターのディープ コピーの作成に関して質問がありました。私が持っているのは、POD でいっぱいのクラス A と、このクラス (A *P) へのポインターです。他のいくつかの POD とクラス A へのポインターのベクトルを含む 2 番目のクラス B があります。ループ内で動的に割り当ておよび割り当て解除するため、A *P のディープ コピーのこのベクトルを埋めたいと思います。以下は動作しません。私のコピーコンストラクターと = 演算子のオーバーロードだと思います。これは私が楽しみと学習のためにやっているものです。

class A
{
   public:  
   .....
   .....
   .....
};

class B
{
   public:  
   B();
  ~B();
   B(const B &Copier);
   B& B::operator=(const B &Overloading);
   vector<A*> My_Container;
   A* Points_a_lot;
   int counter;
 };
B::B()
{
  counter=0;
  Points_a_lot=NULL;
}
B::~B()
{
   for(size_t i=0; i<My_Container.size(); i++)
   {
      delete My_Container[i];
    }
 }
 B::B(const B &Overloading)
 {
     My_Container[counter]=new A(*Overloading.Points_a_lot);
 }
 B& B::operator=(const B &Overloading)
 {
     if(!Overloading.My_Container.empty()) 
     {
         Overloading.My_Container[counter]=new B(*Overloading.Points_a_lot);
      }
      return *this; 
  } 
 int main()
 {  A* p=NULL;
    B Alphabet;
    for(....)
    {
        p=new A;
        //some stuff example p->Member_of_A=3; etc..
        Alphabet.My_Container[Alphabet.counter]=p;
        Alphabet.counter++;
       delete p;
     }
    return 0;
   }

どんな助けでも素晴らしいでしょう。お時間をいただきありがとうございます。必要なライブラリが含まれていると仮定します。

4

5 に答える 5

3

さて、あなたはoperator=が何をすべきかについて非常に混乱しているように私には思えます。演算子のオーバーロードについては、このページをご覧ください。これにより、その機能の正しい道を歩み始めることができます。

次に、質問とは関係なく、フィールド(メンバー変数、what-have-you)をプライベートにする必要がある理由についてこの質問を確認してください。

于 2012-08-23T05:31:33.163 に答える
2

コードには多くのエラーがあります。主なものは、代入演算子とコピーコンストラクターがvectorポインターのを完全にコピーするのではなく、ベクトルの場所にAを配置しようとしていることです。B*代入演算子が行うべきことは、自己代入をチェックした後、ベクトルが指す要素を削除し、ソースオブジェクトのベクトルが指す要素の深いコピーで埋めることです。コピーコンストラクターには、ソースオブジェクトの要素のディープコピーを入力する必要があります。

次に、クラスのベクトルに要素を追加するメソッドを提供し、内部でカウンター変数を設定できるようにする必要があります。ベクトルとカウンターの両方を外部で調整する必要があると、エラーが発生しやすくなります。OOPの利点の1つは、この種のエラーを回避できることです。counterしかし、さらに良いことに、変数を完全に削除します。あなたはそれを必要としません。次にmain、これに簡略化されます。

int main()
{
  B Alphabet;
  for(....)
  {
    A* p = new A;
    //some stuff example p->Member_of_A=3; etc..
    Alphabet.appendElement(p); // B takes ownership, no need to delete in main
  }
}

そしてappendElement可能性があります

class B
{
 public:
  void appendElement(A* element) { myContainer_.push_back(element); }
  // other public methods
 private:
   std::vector<A*> myContainer_;
};

生のポインターの代わりに、ある種の単一所有権のスマートポインターを格納することで、これらすべてをさらに改善できます。つまり、自分で削除することを心配する必要はありません。しかし、それはおそらくこの質問の範囲を超えています。

ここで、ポインターを完全に回避することを検討する必要があります。この場合、コピーコンストラクタ、代入演算子、またはデストラクタを提供する必要はありません。コンパイラで合成されたものは問題なく動作します。あなたのクラスBは

class B
{
 public:
  void appendElement(const A& element) { myContainer_.push_back(element); }
  // other public methods
 private:
   std::vector<A> myContainer_;
};
于 2012-08-23T05:30:06.430 に答える
1

私はあなたの要件が何であるかを完全には理解していないので、コードを修正して、Bあなたが求めているように思われるので、ディープコピーを作成しようとしました.

#include <vector>
using namespace std;

class A
{
public:
    A() : m_someInt(0), m_someFloat(0.0f) {}

    // Redundant but putting it here for you to see when it is called (put break-point)
    A(const A& a_other)
    {
        m_someInt = a_other.m_someInt;
        m_someFloat = a_other.m_someFloat;
    }

    int   m_someInt;
    float m_someFloat;
};

class B
{
public:  
    B();
    ~B();
    B(const B &Copier);
    B& B::operator=(const B &Overloading);
    void Cleanup();
    void AddA(const A* a);

private:

    vector<A*> My_Container;
    A* Points_a_lot;
};

B::B()
{
    Points_a_lot=NULL;
}

B::~B()
{
    Cleanup();
}

B::B(const B &Overloading)
{
    // Deep copy B
    operator=(Overloading);
}

B& B::operator=(const B &Overloading)
{
    // Delete old A's
    Cleanup();

    // Not using iterators to keep it simple for a beginner
    for (size_t i = 0; i < Overloading.My_Container.size(); ++i)
    {
        // We need new A's which will then copy from the A's in Overloading's container
        A* newA = new A( *(Overloading.My_Container[i]) );
        // Done with allocation and copy, push_back to our container
        My_Container.push_back(newA);
    }

    return *this; 
}

void B::Cleanup()
{
    // Assuming B is not responsible for cleaning up Points_a_lot
    Points_a_lot = NULL;

    for (size_t i = 0; i < My_Container.size(); ++i)
    {
        delete My_Container[i];
    }

    // Automatically called when My_Container is destroyed, but here we 
    // are open to the possibiliy of Cleanup() being called by the client
    My_Container.clear(); 
}

void B::AddA(const A* a)
{
    // We are adding a new A. In your code, the incoming A is going to 
    // be destroyed, therefore, we need to allocate a new A and copy 
    // the incoming A
    A* newA = new A(*a);
    My_Container.push_back(newA);
}

int main()
{  
    A* p=NULL;
    B Alphabet;
    for(int i = 0; i < 10; ++i)
    {
        p = new A();
        //some stuff example p->Member_of_A=3; etc..
        Alphabet.AddA(p);
        delete p;
    }

    // If you put a breakpoint here and step through your code, you will see
    // `B` deep-copied
    B NewAlphabet = Alphabet;

    return 0;
}

いくつかのメモ:

  • Newループ内でing とdeleteingを使用するのはよくありません。A学ぶためだけにこれを行っていることはわかっていますが、これは心に留めておく必要があるかもしれません. Aを介して破棄する代わりに、新しいの所有権を取得pできるようにしますBA
  • デバッガーを使用してコードをステップ実行し、その動作を確認します
  • 「なぜこれが機能しない/コンパイルできないのか」と尋ねるときは、できるだけ元のコードに近いコードを投稿するようにしてください
于 2012-08-23T05:57:48.223 に答える
0

をご覧になることをお勧めしますboost::ptr_vector。そのインターフェイスは a のインターフェイスに非常に似ていますがstd::vector、ポインター用に調整されているため、次のようになります。

  • リソースを所有しています(したがって、メモリリークはありません)
  • ポリモーフィック ストレージ (派生クラス) を許可する
  • const-correct および copy-correct です

コピーを機能させるには、A* new_clone(A const*)実装を提供する必要があります。

于 2012-08-23T06:40:43.343 に答える
0

代わりに My_Container を unique_ptrs で構成して、割り当てるときにベクターが A インスタンスの所有権を引き継ぐようにする必要があるようです

for(....)
{
    p=new A;
    //some stuff example p->Member_of_A=3; etc..
    Alphabet.My_Container[Alphabet.counter]=p;
    Alphabet.counter++;
   delete p;
 }

代わりに My_Container を次のように宣言します。

vector<std::unique_ptr<A*> > My_Container;

コードは次のようになります

for(....)
{
    p=new A;
    //some stuff example p->Member_of_A=3; etc..
    Alphabet.My_Container[Alphabet.counter]=p;
    Alphabet.counter++;
 }

次に、「ディープコピー」を行う必要がある場合は、clone() などと呼ばれる A にメンバーを作成unique_ptrし、インスタンスに a を返します。コピーを作成する必要がある場合は、それを使用します。

于 2012-08-23T05:47:59.053 に答える