2012-09-16 10 views
6

Trong lớp học của tôi, tôi có một biến thành viên std::vector<node*> childrenĐó có phải là một rò rỉ bộ nhớ để push_back một con trỏ vào một vector của con trỏ?

Chức năng thành viên của lớp sau có tạo ra rò rỉ bộ nhớ không?

//adds a child node 
{ 
    node* child = new node("blah","blah","blah"); 
    child->Set_Parent(this); 
    children.push_back(child); //<- Is this ok? 
} 

Các vector tạo một bản sao của con trỏ và tôi có hai con trỏ vào bộ nhớ cùng, và sau đó con trỏ gốc đi ra khỏi phạm vi, phải không?

Điều này có thể đơn giản và rõ ràng, nhưng tôi chỉ muốn xác nhận giả định của mình.
cảm ơn

+1

Tôi khuyên bạn nên xem xét các con trỏ thông minh, như ['std :: shared_ptr'] (http://en.cppreference.com/w/cpp/memory/shared_ptr). –

+3

@JoachimPileborg: Bạn thậm chí có thể sử dụng ['std :: unique_ptr'] (http://en.cppreference.com/w/cpp/memory/unique_ptr) trong trường hợp này, như' std :: vector' hỗ trợ các ngữ nghĩa di chuyển. – bitmask

+0

Nếu các nút luôn có bố mẹ, bạn có thể biến nó thành một phần của hàm tạo. Sau đó, bạn chỉ cần 'children.push_back (nút mới (" blah "," blah "," blah "), cái này);' – dtech

Trả lời

12

Nó chưa bị rò rỉ ... Tuy nhiên, nếu số vector vượt quá phạm vi hoặc bạn erase, pop_back hoặc làm điều gì đó khác để xóa các phần tử khỏi vectơ, mà không cần delete nhập phần tử mà bạn đang xóa, bạn sẽ bị rò rỉ trên tay.

Cách đúng để thực hiện việc này là thay đổi từ việc sử dụng vector<node *> thành vector<unique_ptr<node>>. Mã của bạn sẽ thay đổi thành

//adds a child node 
{ 
    node* child = new node("blah","blah","blah"); 
    child->Set_Parent(this); 
    children.push_back(std::unique_ptr<node>(child)); 
} 

Hoặc sử dụng boost::ptr_vector<node> nếu bạn có thể sử dụng Boost.

+0

Vâng, tôi có thể tránh các con trỏ thô, nhưng chúng tôi sẽ không thực hành theo dõi rò rỉ bộ nhớ! :) Không biết tăng có một lớp như thế! thanks –

+4

Dòng cuối cùng có thể đơn giản là 'children.emplace_back (child);' –

2

Chỉ rò rỉ bộ nhớ nếu bạn quên chia nhỏ nút con khi lớp có chứa hàm hủy của vectơ được gọi.

+1

tuyệt vời! cảm ơn bạn. Yeah, destructor của tôi loops qua vector, và xóa từng con trỏ. Tôi không tìm thấy lý do nào để đặt chúng thành null vì các con trỏ sẽ sớm biến mất. –

1

Nó không phải là rò rỉ bộ nhớ. Bạn vẫn có một con trỏ trong vectơ và bạn sẽ có thể giải phóng bộ nhớ khi cần thiết.

1

Khi vectơ đi ra khỏi phạm vi, đó là hàm hủy không phá hủy đối tượng được trỏ tới. Nó phá hủy con trỏ - không làm gì cả.

Mã của bạn đã tạo đối tượng đó qua new. Mã của bạn chịu trách nhiệm xóa đối tượng đó. Nếu bạn không làm như vậy, bạn bị rò rỉ. Nếu bạn làm như vậy để sớm, tức là, trước khi loại bỏ con trỏ khỏi vectơ, bạn thậm chí còn có vấn đề lớn hơn.

-3

Giả sử children là một thành viên của lớp, bạn chỉ cần xóa tất cả các mục trong vectơ trên bộ giải mã lớp.

struct Foo{}; 

class Bar 
{ 
public: 
    Bar(){}; 
    ~Bar() 
    { 
     for(vector<Foo*>::iterator it = children.begin(); it != children.end(); ++it) 
     { 
      SAFE_DELETE((*it)); //use your own macro/template or use delete if you don't have one 
      delete (*it); 
      (*it) = NULL; 
     } 
    } 
    vector<Foo*>children; 
} 

Foo* p = new Foo(); 
children.push_back(p); 

Nếu bạn sử dụng một vector<Foo>child thay vào đó, mỗi push_back trên vector sẽ tạo ra một bản sao của đối tượng gốc phải được lưu trữ, nhưng kể từ khi bạn đang sử dụng con trỏ, trong trường hợp này cấp phát trên heap bởi new không có đối tượng bản sao được tạo ra, con trỏ trỏ đến một đối tượng dài hạn được lưu trữ đơn giản, có nghĩa là có, bạn phải xóa nó sau này.

+0

Điều đó có ý nghĩa.Tôi không nghĩ rằng tôi cần phải đặt chúng để null mặc dù kể từ khi toàn bộ đối tượng sẽ bị phá hủy. Tôi không hiểu mục đích của macro/mẫu. –

+1

Tôi không hiểu đúng, Bạn không nghĩ mình cần đặt con trỏ thành NULL khi xóa nó ?. 'safe_delete' là một macro/mẫu đã biết cho các độ tuổi, mục đích của nó là xóa một mục được phân bổ một cách an toàn. Tôi khuyên bạn nên đọc hiệu quả/hiệu quả hơn C++ từ từ David Mayhew và Scott Meyers. –

+4

Tôi không phải là downvoter, nhưng điều này là ngớ ngẩn. 'SAFE_DELETE' không an toàn; tất cả những gì nó làm là kiểm tra xem con trỏ có null hay không trước khi gọi 'delete'. Không có gì sai khi xóa một con trỏ null. Không cần thử nghiệm đó; không cần sử dụng 'SAFE_DELETE' thay vì chỉ sử dụng' delete'. Để làm cho 'SAFE_DELETE' thực sự an toàn, bằng cách nào đó nó sẽ phải kiểm tra xem một con trỏ không null thực sự được cấp phát với' new' trước khi gọi 'delete'. Nó không làm điều đó. Cũng không có lý do gì để đặt con trỏ thành 'NULL' sau khi xóa nó; chúng ta đang ở trong destructor. –