5

次のバグが発生しています。

  • クラスがありFooます。このクラスのインスタンスは、のstd::vectorvecに格納されclass Bます。
  • クラスFooでは、でnewそのオブジェクトを使用してメモリを割り当てたり削除したりして、クラスAのインスタンスを作成しています~Foo()

コードはコンパイルされますが、実行時にクラッシュします。delete my_aクラスのdesstructorを無効にした場合Foo。コードは正常に実行されます(ただし、メモリリークが発生します)。

誰かがここで何が悪いのかを説明し、修正を提案してもらえますか?

ありがとう!

class A{
      public:
          A(int val);
          ~A(){};
          int val_a;

};

A::A(int val){
       val_a = val;
       };

class Foo {      
      public:
             Foo();
             ~Foo();
             void createA();
             A* my_a;
};

Foo::Foo(){
    createA();
};

void Foo::createA(){
    my_a = new A(20);
};

Foo::~Foo(){
    delete my_a;

};



class B {
      public:
             vector<Foo> vec;             
             void createFoo();            
             B(){};
             ~B(){};
};


void B::createFoo(){
    vec.push_back(Foo());
};


int main(){
    B b;

    int i  =0;
    for (i = 0; i < 5; i ++){
        std::cout<<"\n creating Foo";
        b.createFoo();   
        std::cout<<"\n Foo created";
        }
    std::cout<<"\nDone with Foo creation";

    std::cout << "\nPress RETURN to continue...";
    std::cin.get();

    return 0;
}
4

3 に答える 3

7

Fooのコピーコンストラクターと代入演算子を実装する必要があります。デストラクタが必要な場合は、ほぼ確実にこれら2つも必要です。それらは多くの場所で、特にオブジェクトを標準ライブラリコンテナに入れるために使用されます。

コピーコンストラクタは次のようになります。

Foo :: Foo( const Foo & f ) : my_a( new A( * f.my_a ) ) {
}

および代入演算子:

Foo & Foo :: operator=( const Foo & f ) {
    delete my_a;
    my_a = new A( * f.my_a );
    return * this;
}

さらに良いことに、FooクラスにAインスタンスを動的に作成しないでください。

class Foo {      
      public:
             Foo();
             ~Foo();
             void createA();
             A my_a;
};

Foo::Foo() : my_a( 20 ) {
};
于 2010-04-27T09:20:28.550 に答える
3

コピーコンストラクターを指定しない場合、コンパイラーがコピーコンストラクターを作成します。コンパイラで生成されたコピーコンストラクタは次のようになります。

Foo::Foo(const Foo& copy)
    : my_a(copy.my_a)
{}

おっと!ポインタだけをコピーしていますが、ポイントされたメモリはコピーしていません。一時的な入力とベクトルにコピーされた入力の両方Foo()createFoo()同じメモリを指しているため、メモリが2回削除され、2回目の削除でプログラムがクラッシュします。

次のようなコピーコンストラクタを作成する必要があります。

Foo::Foo(const Foo& copy)
    : my_a(new A(*copy.my_a))
{}

copyNULLメンバーがある場合、これはクラッシュすることに注意してください。また、指定していないでmy_aコピーコンストラクターも呼び出します。Aしたがって、さらにいくつかの変更を加える必要があります。オーバーロードも必要になりoperator=ます。

于 2010-04-27T09:31:13.430 に答える
2

Fooオブジェクトがコピーされ、すべてのコピーが破棄されると、同じポインター値my_aでdeleteが呼び出されます。Fooのコピーおよび代入演算子を実装するか、スマートポインターを使用します。

 Foo( const Foo& s) : my_a( s.my_a ? new A(*s.my_a) : 0) {
 }

 Foo& operator= (const Foo& s) {
     Foo temp(s); 
     temp.swap (*this);
     return *this;
 }

 void swap (Foo &s) { 
     std::swap (my_a, s.my_a);  
 }; 
于 2010-04-27T09:25:51.390 に答える