私有解構函式和刪除解構函式
阿新 • • 發佈:2021-10-20
解構函式 destructor
私有解構函式 private destructor
解構函式是 private
時,那麼當物件銷燬時或對於動態分配的物件,當對指向它的指標應用 delete
運算子時,只有 物件銷燬 所處的上下文環境為成員函式體或友元函式體內部時,才能正常呼叫 private
解構函式,才能正常銷燬物件。其原因是,只有成員函式和友元函式才能訪問類的 private
成員。
所以,(1)當定義一個物件(非動態分配)時,只有 物件定義 所處的上下文環境能夠訪問 private
解構函式時,編譯器才會允許定義該型別的物件。其原因是,如果沒有這條規則,我們可能會創建出無法銷燬的物件。(2)動態分配的物件, new
delete
運算子時,只有 delete
表示式所處的上下文環境能夠訪問 private
解構函式時,才能正常銷燬物件。
其實,將解構函式宣告為 private
幾乎沒有什麼實用意義,因為通常我們的程式設計應該總是使解構函式能夠被通暢地呼叫,而不是設定“障礙”。
#include <iostream> #include <string> #include <memory> class T { friend void FriendDestroy(T* ptr); public: static void StaticDestroy(T* ptr) { delete ptr; } // Destroy() is 'delete this', which looks like very dangerous, not recommended. The more recommended is 'static void StaticDestroy(T* ptr)'. void Destroy() { delete this; } public: void InstanceInMemberFunction() { // ok: destructor 'T::~T()' can normally call within this context T t; } public: T() = default; T(const T&) = default; T(T&&) = default; T& operator=(const T&) = default; T& operator=(T&&) = default; private: ~T() { std::cout << "destructor is called" << std::endl; } private: std::string str_; }; void FriendDestroy(T* ptr) { delete ptr; } int main() { // error: destructor 'T::~T()' is private within this context //T t1; // error: destructor 'T::~T()' is private within this context where '~unique_ptr()' delete pointer //auto t2 = std::make_unique<T>(); // no delete pointer and the memory leak would occur auto t3 = new T(); // error: destructor 'T::~T()' is private within this context //delete t3; auto t4 = new T(); // Destroy() is 'delete this', which looks like very dangerous, not recommended. The more recommended is 'static void StaticDestroy(T* ptr)'. t4->Destroy(); t4 = nullptr; auto t5 = new T(); t5->InstanceInMemberFunction(); T::StaticDestroy(t5); t5 = nullptr; auto t6 = new T(); FriendDestroy(t6); t6 = nullptr; return 0; }
刪除解構函式 deleted destructor
值得注意的是,我們不能刪除解構函式。如果解構函式被刪除,就無法銷燬此型別的物件了。對於一個刪除了解構函式的型別,編譯器將不允許定義該型別的變數或建立該類的臨時物件。而且,如果一個類有某個成員的型別刪除了解構函式,我們也不能定義該類的變數或臨時物件。因為如果一個成員的解構函式是刪除的,則該成員無法被銷燬。而如果一個成員無法被銷燬,則物件整體也就無法被銷燬了。
對於刪除了解構函式的型別,雖然我們不能定義這種型別的變數或成員,但可以動態分配這種型別的物件。但是,不能釋放這些物件。
其實,刪除解構函式幾乎沒有什麼實用意義,因為我們很少需要建立不能銷燬的物件(這時就只能通過動態分配來建立物件了,但不能釋放這些物件)。
#include <iostream>
#include <string>
#include <memory>
class T
{
public:
~T() = delete;
public:
T() = default;
T(const T&) = default;
T(T&&) = default;
T& operator=(const T&) = default;
T& operator=(T&&) = default;
private:
std::string str_;
};
int main()
{
// error: use of deleted destructor function 'T::~T()'
//T t1;
// error: use of deleted destructor function 'T::~T()'
//auto t2 = std::make_unique<T>();
// no delete pointer and the memory leak would occur
auto t3 = new T();
// error: use of deleted destructor function 'T::~T()'
//delete t3;
return 0;
}