2010-03-11 27 views
21

Tôi muốn lớp của mình có một con trỏ tĩnh đến vùng được cấp phát động của bộ nhớ. Tôi hiểu làm thế nào để khởi tạo nó - trong trường hợp của tôi, tôi sẽ khởi tạo nó khi đối tượng đầu tiên cần nó. Tuy nhiên, tôi không biết khi nào/ở đâu trong mã để giải phóng nó. Tôi muốn giải phóng nó khi chương trình chấm dứt.C++ giải phóng các biến tĩnh

Tôi có thể giải phóng con trỏ trong trình phá hủy đối tượng của mình, nhưng sau đó tôi phải duy trì một số đối tượng để xem liệu nó có an toàn để giải phóng khi đối tượng là đối tượng cuối cùng được sử dụng hay không.

Có cách nào thanh lịch hơn để thực hiện việc này không?

Vui lòng cho tôi biết.

Cảm ơn, jbu

+0

SOunds như bạn đang cố gắng tái tạo lại con trỏ thông minh? –

+0

Vấn đề này là một trong những vấn đề xảy ra khi triển khai thực đơn (http://en.wikipedia.org/wiki/Singleton_pattern). Mẫu mã của @ Klaim dưới đây là ví dụ về một mẫu. Chúng có thể là một điều tốt hoặc nạng. Đừng lạm dụng chúng. :) – Void

Trả lời

18

Bạn có hai giải pháp ở đây:

  1. Không xóa xóa nó (bạn đang ở trong C++, bạn sử dụng mới và xóa, phải không;?)) . Hầu như tất cả các hệ điều hành ngày hôm nay sẽ "miễn phí" bộ nhớ được phân bổ bởi ứng dụng nào một khi nó đã hoàn thành. Nhưng đó không phải là một giải pháp tốt, mà làm cho bộ nhớ rò rỉ khó phát hiện ví dụ.
  2. Đóng gói con trỏ của bạn vào một lớp (làm thành viên), sau đó sử dụng lớp này làm loại tĩnh của bạn. Bằng cách đó, bạn biết destructor lớp sẽ được gọi vào cuối ứng dụng. Sau đó bạn chỉ cần xóa dữ liệu của bạn trong destructor và công việc được thực hiện và làm sạch. Đó là sức mạnh của RAII.

Tôi đề nghị bạn làm 2, đó là một cách thực sự sạch sẽ để làm điều đó.


Đây là ví dụ đơn giản. Thay vì làm điều này

static Thing* things = new Thing(); // or whatever way to initialize, here or in a specific function 

Bạn sẽ làm điều đó:

class ThingManager // or whatever name you like 
{ 
public: 
    ThingManager(Thing* thing) : m_thing(thing) { }//or create it here? whatever solution suits your way of creating the data 

    ~ThingManager() { delete m_thing; } // THAT's the important part! 

    Thing* instance() const { return m_thing; } // or whatever accessor you need, if you need one 

private: 
    Thing* m_thing; 
}; 

và sau đó

static ManagedThing thing; // now i can access it via thing.instance() 

Khi chương trình kết thúc, các biến tĩnh (mà không phải là con trỏ nữa) sẽ bị hủy diệt và nó sẽ được gọi để làm điều đó.

Nó được viết chỉ để cung cấp cho bạn một ý tưởng về cách bạn có thể làm điều đó.

+0

Xin lỗi, tôi rất mới với C++. Khi bạn nói "destructor lớp sẽ được gọi là ở cuối của ứng dụng" là bạn nói có một destructor đối tượng và một destructor lớp tĩnh? Ngoài ra, RAII là gì? – jbu

+0

RAII: http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization Bạn nên tìm hiểu về các chức năng mặc định của tất cả các lớp. – Klaim

+4

RAII là một thuật ngữ không may, bởi vì nó không phải là rất mô tả; xem http://en.wikipedia.org/wiki/RAII –

2

Bạn có thể khai báo biến tĩnh như một con trỏ thông minh, sau đó khi chương trình kết thúc con trỏ được cấp phát sẽ được giải phóng.

0

tôi sẽ xác định một bộ đếm tĩnh trong lớp để theo dõi các trường hợp đối tượng đếm như destructor được thực hiện nó giảm các truy cập và nếu truy cập == 0 miễn phí bộ nhớ quá .. cũng giống như bạn

6

Từ hệ điều hành quan điểm, không có điểm thực trong giải phóng bộ nhớ khi chương trình của bạn chấm dứt, tất cả những gì làm là chấm dứt chậm xuống. Chấm dứt ứng dụng của bạn sẽ làm rơi toàn bộ không gian địa chỉ của bạn, nó sẽ miễn phí mọi thứ bạn phân bổ trên heap cùng một lúc. gọi một cách rõ ràng free khi tắt ứng dụng chỉ là xáo trộn con trỏ trong heap sẽ bị vứt bỏ.

Lý do chính tại sao chúng tôi cố gắng hết sức để giải phóng mọi thứ một cách rõ ràng là đảm bảo rằng chúng tôi không bị rò rỉ bộ nhớ và bộ nhớ của chúng tôi không phát triển mãi mãi. Nhưng nếu bạn có thể chắc chắn rằng điều này là tĩnh, rằng sẽ chỉ có một, và bạn không thể giải phóng nó một cách an toàn cho đến khi tất cả các đối tượng khác của bạn được giải phóng, đây là trường hợp nó có thể tốt hơn chỉ để cho ứng dụng chấm dứt chăm sóc nó cho bạn.

+0

Cảm ơn bạn đã phản hồi. Tôi luôn luôn nghĩ rằng rò rỉ bộ nhớ sẽ làm cho hệ điều hành giữ trên bộ nhớ dành riêng/unfreed ngay cả sau khi chấm dứt chương trình. – jbu

+1

@jbu: Nó sẽ không phải là một hệ điều hành rất tốt nếu nó đã làm điều đó. ;) –

+2

Mặc dù nó sẽ che giấu các rò rỉ bộ nhớ khác với một số công cụ phát hiện rò rỉ bộ nhớ, do đó, nó không được recommanded anyway. – Klaim

14

Ném vào con trỏ thông minh. Nó sẽ có tuổi thọ tĩnh và bị phá hủy sau khi main lợi nhuận:

static std::auto_ptr<T> thePointer; 

Một lựa chọn khác là để đăng ký riêng atexit chức năng của bạn:

// static 
void YourClass::freePointer(void) 
{ 
    delete getPointer(); 
} 

// static 
T* YourClass::getPointer(void) 
{ 
    if (!thePointer) 
    { 
     thePointer = new T; 
     atexit(freePointer); 
    } 

    return thePointer; 
} 

nào sẽ có tác dụng tương tự. Một tùy chọn khác mà bạn đã đề cập là giữ một bộ đếm tĩnh. Lưu ý rằng bạn thực sự có thể kết nối nó khá hiệu quả.

+1

Alexandrescu sử dụng 'atexit' trong việc thực hiện' Loki :: Singleton' của mình.Bằng cách này, anh ta đảm bảo rằng các phương thức giải phóng con trỏ cũng đặt lại trạng thái của nó thành '0' để nó có thể được phân bổ lại nếu cần thiết (trường hợp chính sách toàn thời gian' Phoenix'). Cá nhân tôi nghĩ một 'auto_ptr' hoặc thậm chí tốt hơn' unique_ptr' ít gặp rắc rối hơn nhiều. –

+0

Điều này không tốt, chỉ có một số lượng nhỏ chức năng dọn dẹp at_exit, đôi khi thấp tới 32 (mức tối thiểu được xác định trong tiêu chuẩn) – Lothar