2013-07-25 27 views
8

Tôi đang sử dụng std::map để ánh xạ giá trị chuỗi thành MyType *. Khai báo bản đồ của tôi trông giống như sau:Cách đúng để hủy bản đồ có giá trị con trỏ

map<string, MyType *> *my_map = new map<string, MyType>; 

my_map là biến thành viên riêng của một trong các lớp học của tôi. Vấn đề của tôi là tôi không chắc chắn về cách phá hủy bản đồ. Khi xóa bản đồ, tôi cũng muốn gọi delete trên tất cả các MyType * có trong bản đồ. Đây là hiện tại của tôi destructor:

my_map->erase(my_map->begin(), my_map->end()); 
delete my_map; 

Điều này sẽ xóa các con trỏ có trong bản đồ, hoặc tôi cần phải lặp qua bản đồ để xóa từng con trỏ trước khi gọi xóa?

+2

Sau đó - các thùng chứa 'bản đồ' (và hầu hết (nếu không phải tất cả?) Trong thư viện chuẩn) chưa được thiết kế để xóa bất kỳ con trỏ nào nó chứa khi hủy. – Nbr44

+0

Ok cảm ơn. Tài liệu tôi đọc trên đó không rõ ràng lắm. Nó đọc: 'Điều này làm giảm kích thước vùng chứa một cách hiệu quả bởi số lượng các phần tử bị loại bỏ, bị phá hủy.' – Max

+3

Đó là một sự hiểu lầm phổ biến - bản thân _pointers_ thực sự bị phá hủy, nhưng điều đó không thay đổi trạng thái của vị trí bộ nhớ mà chúng trỏ đến . – Nbr44

Trả lời

9

Con trỏ chỉ trỏ. Khi sử dụng con trỏ thô, bạn cần biết phần nào của ứng dụng của bạn sở hữu tài nguyên mà con trỏ trỏ đến. Nếu chúng được sở hữu bởi bản đồ, bạn sẽ cần phải lặp qua bản đồ và gọi xóa trên mỗi con trỏ trước khi bản đồ bị hủy. Nhưng nếu bản đồ chỉ giữ các con trỏ đến các đối tượng được sở hữu bởi các phần khác của mã của bạn, bạn không cần phải làm gì cả.

Giải pháp an toàn hơn là sử dụng shared_ptr để quản lý tuổi thọ đối tượng, điều này sẽ đảm bảo rằng đối tượng bị xóa đúng cách khi shared_ptr cuối cùng bị hủy. Bạn có thể lưu trữ shared_ptrs bên trong bản đồ và nếu không có cá thể shared_ptr nào khác tham chiếu các đối tượng trong bản đồ, các đối tượng sẽ bị hủy khi bản đồ bị hủy, như mong muốn.

2

Nếu bạn sử dụng smart pointers thay vì con trỏ thô, mọi thứ sẽ tự động được dọn sạch cho bạn.

// header: 
using MapType = std::map<std::string, std::shared_ptr<MyType>>; 
shared_ptr<MapType> my_map; 

// usage: 
my_map.emplace("foo", std::make_shared<MyType>()); 

// destructor: 
MyClass::~MyClass() 
{ 
    // nothing! 
} 
3

Điều này sẽ xóa con trỏ có trong bản đồ [...]?

Không, với mã bạn đã cung cấp, bạn sẽ làm rò rỉ mọi thành viên của bản đồ.

Theo quy tắc, đối với mỗi new, phải có một số delete phù hợp. Bạn có một delete cho bản đồ, nhưng không có gì cho các phần tử bên trong.

Giải pháp chính xác nhất cho vấn đề này là không sử dụng phân bổ động. Chỉ cần lưu thư mục MyType s, nếu có thể:

map<string, MyType>

... và thay vì tự động phân bổ các map bản thân, lưu trữ tự động:

map<string,MyType> my_map; 

Nếu thời gian lưu trữ tự động là không thể đối với một số lý do, sau đó sử dụng một con trỏ thông minh cho phân bổ động. Với một trình biên dịch C++ 11, sử dụng unique_ptr (hoặc hiếm gặp hơn, hoặc thậm chí shared_ptrweak_ptr) cho các yếu tố trong map:

map<string, unique_ptr<MyType>> my_map; 

(Với một trình biên dịch C++ 03, sử dụng các khoản tương đương Boost đó.) Sau đó, khi my_map bị hủy, tất cả các thành phần sẽ là delete d.

Baring tất cả điều này, nếu bạn đang ở trong một tình huống mà không có ở trên sẽ làm việc cho bạn (tôi sẽ bởi rất nghi ngờ), sau đó bạn sẽ cần phải lặp bản đồ khỏang:

struct deleter 
{ 
    template <typename T> operator() (const T& rhs) const 
    { 
    delete rhs.second; 
    } 
}; 

for_each (my_map->begin(), my_map->end(), deleter()); 

Trong C++ 11, điều này có thể được thực hiện một lambda, một cái gì đó dọc theo dòng:

for_each (my_map->begin(), my_map->end(), [](auto item) -> void 
{ 
    delete item.second; 
}); 
1

trong C++ hiện đại, chỉ cần làm cho cuộc sống dễ dàng hơn và sử dụng con trỏ chỉ nếu có yêu cầu nghiêm ngặt.

Bạn bắt đầu với mã này:

map<string, MyType *> *my_map = new map<string, MyType>; 

Điều đầu tiên bạn có thể làm là xem xét sử dụng một trường hợp std::map như thành viên dữ liệu, thay vì một con trỏ với nó.

Sau đó, nếu MyType không phải là siêu đắt để sao chép và trường hợp của nó chỉ thuộc sở hữu của bản đồ, chỉ cần xem xét một đơn giản map từ string để MyType (thay vì MyType*):

// my_map data member - no pointers --> automatically deleted in class destructor 
map<string, MyType> my_map; 

Nếu bạn thực sự cần bản đồ chứa con trỏ, hãy xem xét sử dụng các con trỏ thông minh thông minh, như std::shared_ptr (có sẵn trong C++ 11/14) để chia sẻ quyền sở hữu hoặc std::unique_ptr cho quyền sở hữu không chia sẻ duy nhất.
(Nếu bạn nhắm mục tiêu C++ 98/03, một tùy chọn là sử dụng boost::shared_ptr Vì không có ngữ nghĩa di chuyển, bạn không thể có unique_ptr, được chủ yếu dựa vào động thái ngữ nghĩa đặc trưng..)
ví dụ:

// Map containing _smart_ pointers 
//  --> default destructor is fine (no need for custom delete code) 
map<string, shared_ptr<MyType>> my_map; 

Như bạn thấy, sử dụng ngữ nghĩa giá trị (thay vì con trỏ nguyên), hoặc con trỏ thông minh, bạn có thể đơn giản hóa mã của bạn và sử dụng tự động phá hủy cung cấp bởi C++.

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