当标准 delete 不适用于释放、释放、丢弃或以其他方式处置其生命周期由智能指针控制的资源时,您需要为智能指针创建提供自己的删除。
智能指针的典型用途是将内存分配为由智能指针管理的资源,这样当智能指针超出范围时,被管理的资源(在这种情况下为内存)通过使用 @ 丢弃987654329@运营商。
标准的delete 操作符做了两件事:(1) 调用对象的析构函数以允许对象在其分配的内存被释放或解除分配之前执行它需要做的任何清理工作;(2) 释放已分配的内存由构造对象时的标准new 运算符。这是 new 操作符发生的相反顺序,它 (1) 为对象分配内存并执行为对象建立构造环境所需的基本初始化,以及 (2) 调用对象的构造函数来创建对象的起始状态。见What does the C++ new operator do other than allocation and a ctor call?
因此,需要您自己的删除器的关键问题是“在对象的析构函数完成后,在调用对象构造函数之前执行的哪些操作需要展开并退出?”。
通常这是某种类型的内存分配,例如由标准 new 运算符完成。
但是,对于使用new 运算符分配的内存以外的某些资源,使用delete 运算符是不合适的,因为该资源不是使用new 运算符分配的内存。
因此,当在 delete 运算符不适合的此类资源中使用智能指针时,您需要提供自己的删除器方法或函数或运算符,当智能指针超出范围并触发时将使用它们它自己的析构函数将依次处理丢弃由智能指针管理的任何资源。
一个简单的输出示例
我将一个简单的示例与std::unique_ptr<> 放在一起,以及生成的输出显示使用和不使用带有指针的删除器以及显式使用析构函数。
一个简单的 Windows 控制台应用程序的源代码如下所示:
// ConsoleSmartPointer.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <memory>
#include <string>
#include <iostream>
class Fred {
public:
Fred() { std::cout << " Fred Constructor called." << std::endl; }
~Fred() { std::cout << " Fred Destructor called." << std::endl; }
};
class George {
public:
George() { std::cout << " George Constructor called" << std::endl; }
~George() { std::cout << " George Destructor called" << std::endl; }
private:
int iSomeData;
std::string a_label;
Fred myFred;
};
void cleanupGeorge(George *)
{
// just write out a log and do not explicitly call the object destructor.
std::cout << " cleanupGeorge() called" << std::endl;
}
void cleanupGeorge2(George *x)
{
// write out our message and then explicitly call the destructor for our
// object that we are the deleter for.
std::cout << " cleanupGeorge2() called" << std::endl;
x->~George(); // explicitly call destructor to do cleanup.
}
int func1()
{
// create a unique_ptr<> that does not have a deleter.
std::cout << "func1 start. No deleter." << std::endl;
std::unique_ptr<George> p(new George);
std::cout << "func1 end." << std::endl;
return 0;
}
int func2()
{
// create a unique_ptr<> with a deleter that will not explicitly call the destructor of the
// object created.
std::cout << "func2 start. Special deleter, no explicit destructor call." << std::endl;
std::unique_ptr<George, void(*)(George *)> p(new George, cleanupGeorge);
std::cout << "func2 end." << std::endl;
return 0;
}
int func3()
{
// create a unique_ptr<> with a deleter that will trigger the destructor of the
// object created.
std::cout << "func3 start. Special deleter, explicit destructor call in deleter." << std::endl;
std::unique_ptr<George, void(*)(George *)> p(new George, cleanupGeorge2);
std::cout << "func3 end." << std::endl;
return 0;
}
int main()
{
func1();
func2();
func3();
return 0;
}
上面的简单应用程序生成以下输出:
func1 start. No deleter.
Fred Constructor called.
George Constructor called
func1 end.
George Destructor called
Fred Destructor called.
func2 start. Special deleter, no explicit destructor call.
Fred Constructor called.
George Constructor called
func2 end.
cleanupGeorge() called
func3 start. Special deleter, explicit destructor call in deleter.
Fred Constructor called.
George Constructor called
func3 end.
cleanupGeorge2() called
George Destructor called
Fred Destructor called.
其他帖子
What is a smart pointer and when should I use one?
Using custom deleter with std::shared_ptr
还可以查看有关 std::make_shared<> 的删除器的讨论以及为什么它不可用。 How to pass deleter to make_shared?
Is custom deleter for std::unique_ptr a valid place for manual call to destructor?
When does std::unique_ptr<A> need a special deleter if A has a destructor?
RAII and smart pointers in C++