2010-04-27 59 views
5

Tôi đang gặp phải lỗi sau.câu hỏi phân bổ bộ nhớ liên quan đến vector

  • Tôi có một lớp Foo. Các cá thể của lớp này được lưu trữ trong một tiêu chuẩn :: vector vec của class B.
  • trong lớp Foo, tôi đang tạo một phiên bản lớp A bằng cách cấp phát bộ nhớ bằng cách sử dụng new và xóa đối tượng đó trong ~Foo().

biên dịch mã, nhưng tôi gặp sự cố khi chạy. Nếu tôi vô hiệu hóa delete my_a từ người cố vấn của lớp Foo. Mã chạy tốt (nhưng sẽ bị rò rỉ bộ nhớ).

Ai đó có thể giải thích điều gì đang xảy ra ở đây và đề xuất sửa lỗi?

cảm ơn bạn!

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

Trả lời

7

Bạn cần triển khai trình tạo bản sao và toán tử gán cho Foo. Bất cứ khi nào bạn tìm thấy bạn cần một destructor, bạn alnmost chắc chắn cần hai là tốt. Chúng được sử dụng ở nhiều nơi, đặc biệt để đưa các đối tượng vào các thùng chứa của Thư viện chuẩn.

Các constructor sao chép sẽ trông như thế này:

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

và toán tử gán:

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

Hoặc vẫn tốt hơn, không tạo ra một ví dụ trong lớp Foo động:

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

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

Cảm ơn Neil. Làm thế nào tôi nên tạo ví dụ của lớp A sau đó? Đoạn mã sẽ được nhiều người đánh giá cao. Ngoài ra, làm thế nào sẽ sao chép constructur và chuyển nhượng mã điều hành như thế nào. Cảm ơn rất nhiều – memC

+1

Neil bạn có lỗi đánh máy ... mới A (f.my_a); -> mới A (* f.my_a); – TimW

+0

hi Neil, cảm ơn rất nhiều vì đoạn mã. Trên thực tế, tôi muốn chuyển 'int val' cho' my_a' trong khi đặt cá thể Foo trong vectơ. Làm thế nào để làm điều đó? -> Tôi muốn một cái gì đó như thế này: (Tất nhiên nó không hoạt động) 'vec.push_back (Foo(): my_a (40)' – memC

2

Đối tượng Foo được sao chép và hủy diệt mọi bản sao, xóa được gọi trên giá trị con trỏ ame my_a. Thực hiện thao tác sao chép và gán cho Foo hoặc sử dụng con trỏ thông minh.

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 cho con trỏ thông minh – hamishmcn

+0

cảm ơn Tim cho câu trả lời. – memC

3

Nếu bạn không chỉ định một hàm tạo bản sao, trình biên dịch sẽ tạo cho bạn. Trình tạo bản sao do trình biên dịch tạo ra của bạn trông giống như sau:

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

Woops! Bạn chỉ sao chép con trỏ chứ không phải bộ nhớ chỉ vào. Cả hai tạm thời của bạn Foo() trong createFoo() và một được sao chép vào điểm vector vào cùng một bộ nhớ, do đó bộ nhớ bị xóa hai lần, làm hỏng chương trình của bạn trên lần xóa thứ hai.

Bạn nên tạo một constructor sao chép mà trông giống như sau:

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

Chú giải này bị treo nếu copy có NULL my_a thành viên, và nó cũng gọi các nhà xây dựng bản sao trên A, mà bạn chưa xác định hoặc. Vì vậy, bạn sẽ muốn thực hiện thêm một số thay đổi. Bạn cũng sẽ muốn có quá tải operator=.

Các vấn đề liên quan