Việc sử dụng có hàm hủy là riêng tư là gì?


Câu trả lời:


176

Về cơ bản, bất cứ khi nào bạn muốn một số lớp khác chịu trách nhiệm về vòng đời của các đối tượng của lớp bạn hoặc bạn có lý do để ngăn chặn sự phá hủy của một đối tượng, bạn có thể đặt công cụ phá hủy ở chế độ riêng tư.

Chẳng hạn, nếu bạn đang thực hiện một số cách đếm tham chiếu, bạn có thể để đối tượng (hoặc người quản lý là "bạn bè" ed) chịu trách nhiệm đếm số lượng tham chiếu cho chính nó và xóa nó khi số đó bằng không. Một dtor riêng sẽ ngăn không cho bất kỳ ai khác xóa nó khi vẫn còn các tài liệu tham khảo đến nó.

Trong một trường hợp khác, nếu bạn có một đối tượng có trình quản lý (hoặc chính nó) có thể phá hủy nó hoặc có thể từ chối phá hủy nó tùy thuộc vào các điều kiện khác trong chương trình, chẳng hạn như kết nối cơ sở dữ liệu đang mở hoặc tệp được ghi. Bạn có thể có một phương thức "request_delete" trong lớp hoặc trình quản lý sẽ kiểm tra điều kiện đó và nó sẽ xóa hoặc từ chối và trả về trạng thái cho bạn biết những gì nó đã làm. Điều đó linh hoạt hơn nhiều khi chỉ cần gọi "xóa".


73

Một đối tượng như vậy không bao giờ có thể được tạo ra trên ngăn xếp. Luôn luôn trên đống. Và việc xóa phải được thực hiện thông qua một người bạn hoặc một thành viên. Một sản phẩm có thể sử dụng một hệ thống phân cấp Đối tượng duy nhất và trình quản lý bộ nhớ tùy chỉnh - các tình huống như vậy có thể sử dụng một dtor riêng.

#include <iostream>
class a {
    ~a() {}
    friend void delete_a(a* p);
};


void delete_a(a* p)  {
    delete p;
}

int main()
{
    a *p = new a;
    delete_a(p);

    return 0;
}

19
Sửa chữa: Một đối tượng như vậy có thể được tạo trên ngăn xếp (nhưng chỉ trong phạm vi của một người bạn hoặc chính nó).
Thomas Eding

Ngoài ra, nó không thể ba đối tượng tĩnh hoặc toàn cục (nghĩa là có "thời lượng lưu trữ tĩnh") trong một triển khai được lưu trữ (vì hàm hủy sẽ được gọi khi thoát khỏi chương trình).
Peter - Tái lập Monica

45

Khi bạn không muốn người dùng truy cập vào hàm hủy, tức là bạn muốn đối tượng chỉ bị phá hủy thông qua các phương tiện khác.

http://bloss.msdn.com/larryosterman/archive/2005/07/01/434684.aspx đưa ra một ví dụ, trong đó đối tượng được tham chiếu đếm và chỉ nên bị phá hủy bởi chính đối tượng khi số đếm về 0.


17

COM sử dụng chiến lược này để xóa cá thể. COM làm cho hàm hủy riêng tư và cung cấp giao diện để xóa thể hiện.

Dưới đây là một ví dụ về phương thức Phát hành sẽ như thế nào.

int MyRefCountedObject::Release() 
{
 _refCount--;
 if ( 0 == _refCount ) 
 {
    delete this;
    return 0;
 }
 return _refCount;
}

Các đối tượng COM ATL là một ví dụ điển hình của mẫu này.


8

Thêm vào các câu trả lời đã có mặt ở đây; Các hàm tạo và hàm hủy riêng tư khá hữu ích trong khi thực hiện một nhà máy nơi các đối tượng được tạo được yêu cầu phải được phân bổ trên heap. Nói chung, các đối tượng sẽ được tạo / xóa bởi một thành viên tĩnh hoặc bạn bè. Ví dụ về cách sử dụng thông thường:

class myclass
{
public:
    static myclass* create(/* args */)  // Factory
    {
        return new myclass(/* args */);
    }

    static void destroy(myclass* ptr)
    {
        delete ptr;
    }
private:
    myclass(/* args */) { ... }         // Private CTOR and DTOR
    ~myclass() { ... }                  // 
}

int main ()
{
    myclass m;                          // error: ctor and dtor are private
    myclass* mp = new myclass (..);     // error: private ctor
    myclass* mp = myclass::create(..);  // OK
    delete mp;                          // error: private dtor
    myclass::destroy(mp);               // OK
}

7

Lớp chỉ có thể bị xóa bởi chính nó. Hữu ích nếu bạn đang tạo một số thử đối tượng đếm tham chiếu. Sau đó, chỉ có phương thức phát hành có thể xóa đối tượng, có thể giúp bạn tránh lỗi.


3

Tôi biết bạn đã hỏi về hủy diệt tư nhân. Đây là cách tôi sử dụng những người được bảo vệ. Ý tưởng là bạn không muốn xóa lớp chính thông qua con trỏ đến lớp có thêm chức năng bổ sung cho lớp chính.
Trong ví dụ dưới đây, tôi không muốn GuiWindow bị xóa thông qua con trỏ HandlerHolder.

class Handler
{
public:
    virtual void onClose() = 0;
protected:
    virtual ~Handler();
};

class HandlerHolder
{
public:
    void setHandler( Handler* );
    Handler* getHandler() const;
protected:
    ~HandlerHolder(){}
private:
    Handler* handler_;
};

class GuiWindow : public HandlerHolder
{
public:
    void finish()
    {
        getHandler()->onClose();
    }

    virtual ~GuiWindow(){}
};

3

dirkgently là sai. Dưới đây là một ví dụ về đối tượng với c-tor và d-tor riêng được tạo trên stack (Tôi đang sử dụng hàm thành viên tĩnh ở đây, nhưng nó cũng có thể được thực hiện với chức năng kết bạn hoặc lớp bạn bè).

#include <iostream>

class PrivateCD
{
private:
    PrivateCD(int i) : _i(i) {};
    ~PrivateCD(){};
    int _i;
public:
    static void TryMe(int i)
    {
        PrivateCD p(i);
        cout << "inside PrivateCD::TryMe, p._i = " << p._i << endl;
    };
};

int main()
{
    PrivateCD::TryMe(8);
};

Mã này sẽ tạo đầu ra: bên trong PrivateCD :: TryMe, p._i = 8


3
Tôi khá chắc chắn rằng dirkgently có nghĩa là mã sử dụng lớp của bạn không thể khởi tạo lớp trên ngăn xếp. Tất nhiên bạn vẫn có thể khởi tạo lớp trên ngăn xếp trong các phương thức lớp, vì trong bối cảnh đó, bạn có thể truy cập các bộ nhớ riêng.
Edward Loper

2

Nó có thể là một cách để giải quyết vấn đề trong Windows khi mỗi mô-đun có thể sử dụng một đống khác nhau, chẳng hạn như đống Debug . Nếu vấn đề đó không được xử lý chính xác thì những điều xấu có thể xảy ra.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.