• 私有析构函数和删除析构函数


    析构函数 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;
    }
    
  • 相关阅读:
    web 学习资源整理
    CodeSmith 学习资料收集
    常用 T_SQL 语句
    SQL Server 2000查询分析器自定义查询快捷键
    插入标识列 identity_insert
    c# 上传FTP文件
    (.Net 3.5Sp1)WebForm使用System.Web.Routing
    SPQuery.ViewAttributes
    ChatterBot之linux下安装mongodb 02
    linux端口开放指定端口的两种方法
  • 原文地址:https://www.cnblogs.com/ltimaginea/p/15429828.html
Copyright © 2020-2023  润新知