2010-07-27 60 views
13

Tôi đã tìm kiếm StackOverflow nhưng không thể tìm thấy câu trả lời cho câu hỏi này.Cách đúng để giải phóng std :: vector của con trỏ trong C++ là gì?

Giả sử tôi có một số std::vector<Day *> vector_day - tức là - vectơ con trỏ đến đối tượng Day. Bây giờ tôi push_back để vector_day nhiều yếu tố:

vector_day.push_back(new Day(12)); 
vector_day.push_back(new Day(99)); 
vector_day.push_back(new Day(71)); 
... 

Bây giờ tại một số điểm tôi không còn cần vector_day. Thế nào là đúng cách để giải phóng bộ nhớ?

Nó này một cách chính xác:

for (std::vector<Day *>::iterator i = vector_day.begin(); i != vector_day.end(); ++i) { 
    delete *i; 
} 

Không này làm mất hiệu lực vector trên mỗi xóa? Tôi rất bối rối.

+0

Có thể là một dupe của http://stackoverflow.com/questions/3054567/right-way-to-deallocate-an-stdvector-object –

+0

RC - không thực sự, điều này là hoàn toàn khác. – bodacydo

+1

Không đặt con trỏ vào như vậy. Điều gì sẽ xảy ra nếu ngoại lệ được ném giữa công cụ thời gian ở trong vectơ và nơi bạn xóa tất cả? Bạn sẽ bỏ qua nó và bị rò rỉ. Sử dụng một con trỏ thông minh, hoặc một container con trỏ, không bao giờ con trỏ thô. – GManNickG

Trả lời

16

Cách tốt nhất là không đặt con trỏ vào vectơ ngay từ đầu nếu bạn không hoàn toàn cần. Nhưng nếu bạn thực sự cần phải có một véc tơ của con trỏ, thì cách bạn đang thực hiện nó chỉ là tốt (nhưng .clear() các từ sau vector, nếu nó sẽ không bị phá hủy ngay lập tức, vì vậy nó không đầy lủng lẳng con trỏ)

tuyên bố

delete *it; 

không ảnh hưởng đến các iterator. Nó không thay đổi trình lặp, làm mất hiệu lực trình vòng lặp hoặc loại bỏ con trỏ được trình vòng lặp nhắc đến từ bộ sưu tập. Tất cả nó làm là miễn phí bộ nhớ mà con trỏ được gọi bởi các điểm lặp tại. Con trỏ chính nó phải được loại bỏ khỏi bộ sưu tập một cách riêng biệt.

+0

Cảm ơn bạn đã giải thích. Vì vậy, khi vectơ đi ra khỏi phạm vi, con trỏ sẽ bị xóa tự động, đúng không? – bodacydo

+1

@bodacydo: Đúng vậy. Nếu bạn thực hiện lệnh 'delete * it' ngay trước khi' vectơ' ra khỏi phạm vi, đừng lo lắng về việc gọi 'clear()'. –

0

Thao tác thêm hoặc xóa các phần tử khỏi mảng có thể làm mất hiệu lực các trình vòng lặp, kiểm tra tài liệu cho các quy tắc cụ thể cho các loại vùng chứa khác nhau. Với delete, bạn đang hành động trên dữ liệu chứa trong các phần tử mảng, không phải trên hình dạng của mảng. Iterator đi qua hình dạng của container, họ không quan tâm đến nội dung của nó.

+0

Bây giờ tôi hiểu rõ hơn về hiệu lực. Cảm ơn câu trả lời của bạn! – bodacydo

0

Trước hết, bạn đã chuyển từ i thành it, nhưng tôi cho rằng đó chỉ là lỗi đánh máy.

Nhưng để trả lời nhiệm vụ của bạn, không, điều đó tốt. Bạn không thay đổi it, bạn đang thay đổi *it.

+0

Tôi đã sửa lỗi của 'nó' đang được sử dụng cho' i'. Cảm ơn vì đã phát hiện ra nó. Điều gì sẽ xảy ra nếu tôi thực hiện 'i = 0xAABBCCDD' trong vòng lặp - thay đổi rõ ràng' i' và không phải 'nó', điều đó có làm mất hiệu lực vectơ không? – bodacydo

1

Có thể bạn đang sử dụng một số loại con trỏ được quản lý, rất có thể là con trỏ được chia sẻ.

Nếu bạn xóa véc tơ trong khi người khác vẫn đang giữ một trong những con trỏ đó, bạn sẽ nhận được một số hành vi rất khó chịu nếu họ cố gắng dereference nó. Một con trỏ được chia sẻ sẽ giúp bạn tiết kiệm rằng nhức đầu.

Nếu bạn có thể đảm bảo rằng không có gì khác sẽ tham chiếu con trỏ sau khi vectơ bị xóa, thì bạn vẫn có thể hưởng lợi từ việc sử dụng con trỏ tự động. Nó sẽ quản lý deallocation cho bạn khi vector bị phá hủy. Chi phí là tối thiểu, và nó làm cho cuộc sống của bạn dễ dàng hơn nhiều.

+0

Tôi muốn dùng unique_ptr, chắc chắn không phải auto_ptr. – Gabriel

0

Nó ổn. Bạn đang xóa *i (đối tượng được trỏ bởi phần tử của vectơ) và không phải là i (phần tử của vectơ), do đó vectơ không bị vô hiệu.

Xem this question cho trường hợp nhà phát triển cũng muốn xóa tất cả i s và để giải pháp cho nó (vector_day.clear()) sau vòng lặp.

3

C Một ++ cách để làm điều này là để xác định một struct helper:

struct delete_ptr { // Helper function to ease cleanup of container 
    template <typename P> 
    void operator() (P p) { 
     delete p; 
    } 
}; 

và sau đó sử dụng các thuật toán:

std::for_each(vector_day.begin(), vector_day.end(), delete_ptr()); 
vector_day.clear(); 
2

Nói chung trong C++, bạn nên che giấu quản lý bộ nhớ càng nhiều càng tốt để tránh lỗi bộ nhớ. Trừ khi bạn đang thực hiện rất nhiều việc sao chép các con trỏ và quan tâm rất nhiều về hiệu suất, tôi sẽ chỉ sử dụng shared_ptr.

Đó là một phần của tiêu chuẩn TR1 và có sẵn trong hầu hết các trình biên dịch C++ hiện đại ra khỏi hộp (http://anteru.net/2008/09/01/260/) và rất tuyệt vời để quản lý bộ nhớ lửa và quên.

+1

Hoặc trước hết bạn nên xem unique_ptr. – DanDan

5

Boost ptr_vector để giải cứu!

Liệu chính xác những gì bạn cần, mà không cần phải lặp và xóa các nội dung của std :: vector

0

Dưới đây là một lớp tiện dụng tôi đã viết một thời gian trước khi giao dịch với cùng một vấn đề. Tôi đã chuyển đổi một số mã từ các vector và danh sách dựa trên RogueWave cũ sang các vectơ và danh sách dựa trên STL, và cần một số cách để mô phỏng phương thức clearAndDestroy() của RW cho các danh sách con trỏ. Phương thức clearAndDestroy() có thể được ghi đè để xử lý các kiểu cấu trúc khác nhau (tôi chỉ bao gồm vectơ ở đây cho ngắn gọn).

class StlUtils 
{ 
    public: 

     /** 
     * This method provides a templated way to destroy a std::vector 
     * full of pointers. It is basically a replacement for the RW 
     * vector class' clearAndDestroy methods. The list argument is 
     * returned empty. 
     * 
     * @param list the list of pointers to be destroyed. 
     */ 
     template<class T> static void clearAndDestroy(
     std::vector<T*> &itemList) 
     { 
     for_each(itemList.begin(), itemList.end(), 
        stl_deleter<T>()); 
     itemList.clear(); 
     } 

    private: 

     /** 
     * Templated member function for use with the clearAndDestroy() 
     * method. It provides the method needed by for_each to do the 
     * actual deletion. 
     */ 
     template<class T> struct stl_deleter 
     { 
     void operator() (T* x) { 
      if (x != NULL) 
       delete x; 
     } 
     }; 
}; 
+0

Bạn được phép xóa con trỏ null (sẽ không làm gì cả), vì vậy nếu không thực sự cần thiết. – ollb

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