2010-04-27 22 views
5

我遇到以下錯誤。向量相關的內存分配問題

  • 我有一個類Foo。此類的實例存儲在class B的std :: vector vec中。
  • 在Foo類中,我通過使用new分配內存並刪除~Foo()中的對象來創建類A的實例。

代碼編譯,但我在運行時崩潰。如果我從Foo類的desstructor中禁用delete my_a。代碼運行正常(但會出現內存泄漏)。

有人能解釋一下這裏出了什麼問題,並提出修復建議嗎?

謝謝!

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

回答

7

您需要爲Foo實現複製構造函數和賦值運算符。每當你發現你需要一個析構函數,你幾乎肯定也需要這兩個。它們在許多地方使用,特別是將對象放入標準庫容器中。

拷貝構造函數應該是這樣的:

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類創建一個實例:

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

Foo::Foo() : my_a(20) { 
}; 
+0

謝謝尼爾。那麼我應該如何創建類A的實例呢?代碼片段將非常感謝。另外,如何複製構造函數和賦值運算符代碼。非常感謝 – memC 2010-04-27 09:27:05

+1

尼爾你有一個錯字...新的A(F。my_a); - > new A(* f.my_a); – TimW 2010-04-27 09:37:26

+0

嗨尼爾,非常感謝代碼片段。實際上,我想在將Foo實例放入向量中時將'int val'傳遞給'my_a'。我怎麼做? - >我想要這樣的東西:(當然它不起作用)'vec.push_back(Foo():my_a(40)' – memC 2010-04-27 09:43:16

2

Foo對象被複制並在銷燬每一個副本時,在s上調用delete ame指針值my_a。 爲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); 
}; 
+0

+1智能指針 – hamishmcn 2010-04-27 09:38:57

+0

謝謝Tim的解答。 – memC 2010-04-27 09:44:41

3

如果您未指定複製構造函數,則編譯器將爲您創建一個。編譯器生成的拷貝構造器如下所示:

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

Woops!你只是複製指針而不是指向內存。你的臨時Foo()createFoo()和複製到vector中的那個指向同一個內存,所以內存被刪除兩次,這會在第二次刪除時崩潰你的程序。

您應該創建一個拷貝構造函數,看起來是這樣的:

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

注意這個崩潰,如果copy有一個NULL my_a成員,而且還調用上A拷貝構造函數,你還沒有指定無論是。所以你會想做一些進一步的改變。你也需要一個operator=超負荷。