析构函数 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;
}