惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

U
Unit 42
GbyAI
GbyAI
人人都是产品经理
人人都是产品经理
T
Tor Project blog
Google DeepMind News
Google DeepMind News
The Register - Security
The Register - Security
爱范儿
爱范儿
雷峰网
雷峰网
MongoDB | Blog
MongoDB | Blog
Vercel News
Vercel News
美团技术团队
博客园 - 三生石上(FineUI控件)
D
DataBreaches.Net
L
LangChain Blog
IT之家
IT之家
博客园_首页
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Last Week in AI
Last Week in AI
博客园 - 【当耐特】
T
Tailwind CSS Blog
M
MIT News - Artificial intelligence
P
Proofpoint News Feed
Hacker News: Ask HN
Hacker News: Ask HN
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
量子位
Project Zero
Project Zero
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 聂微东
T
Tenable Blog
aimingoo的专栏
aimingoo的专栏
P
Proofpoint News Feed
T
Threat Research - Cisco Blogs
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Cyberwarzone
Cyberwarzone
C
CERT Recently Published Vulnerability Notes
Microsoft Azure Blog
Microsoft Azure Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园 - 叶小钗
Know Your Adversary
Know Your Adversary
L
Lohrmann on Cybersecurity
C
Cisco Blogs
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Schneier on Security
Schneier on Security
I
InfoQ
P
Privacy & Cybersecurity Law Blog
Spread Privacy
Spread Privacy
Martin Fowler
Martin Fowler
腾讯CDC
S
Security @ Cisco Blogs
F
Fortinet All Blogs

博客园 - 泉子

算法题:求一个序列S中所有包含T的子序列(distinct sub sequence) Django模板输出Dict所有Value的效率问题 笔记:LNK2001不代表链接器真的需要链接相关符号 Windows Restart Manager 重启管理器 advapi32.dll kernel32.dll 中的两套注册表API 使用GDI+保存带Alpha通道的图像(续) 使用GDI+保存带Alpha通道的图像 窗口销毁的相关函数与消息,ActiveX控件的销毁 两个数之间的最短路径问题 C/C++函数中局部对象的构造与析构时机 四年记——身在中小企业 C++ Const总结 [转载]怎样用VB编写.DLL动态链接库文件 Visual Studio 6.0编译PWLib1.12总结 在Windows上编译PWLib 金山词霸没落了么? SendInput模拟键盘输入的问题 数组变量在取地址时回归:不再是指针 创建用于非Visual C++工具的DLL——VB调用C++ DLL为何必须使用def文件 - 泉子
为什么不能将ptr_fun(operator delete)传递给For_Each
泉子 · 2011-08-22 · via 博客园 - 泉子

正在写的一段程序,需要将指针存入一个数组。出于简洁的考虑,不想用智能指针——若要使用智能指针,则必须再给智能指针加上一层包装,以屏蔽掉穿透性的取址操作符(见ATL::CAdapt)。

因此,析构元素的操作就不得不自已动手了——erase前,得先对要删除的元素手动delete。

std::for_each(objects.begin(), objects.end(), …);

在清空数组时,需要对每个元素调用delete,很自然写出for_each时,问题来了,第三个参数传什么?stl提供了类似C#委托的函数包装对象,可以把全局delete关键词封装为函数对象吗?为此,特意百度了一下。结果还真有,像下面这样:

std::for_each(objects.begin(), objects.end(), ptr_fun(operator delete));

不过,讨论者也说了,这个使用可以编译通过,但是只能释放内存,不能调用析构函数。有人提出了一些理由,诸如对迭代器的解引用,以及operator delete与delete operator有差别等等,以及thinking in C++中的解释。大伙的讨论让我看得很晕,但真正的理由,在我看来只有一个,那就是类型信息的缺失。

我们知道,delete执行两个操作:

1. 调用对象的析构函数。

2. 将对象内存归还堆。

要执行第一步操作,就必须知道对象的类型。delete如何知道对象是什么类型?这只能通过调用处的代码上下文与多态支持,而不可能是运行时类型识别——最初的C++并不支持运行时类型识别,而且,就算支持,C++对效率的一贯追求也不允许在delete时使用运行时类型识别。

因此,在调用delete时,必须传递目标类型或其基类的指针,当传递基类指针时,要求该类族必须使用虚拟析构函数。C++类的自定义delete操作符以void*作为参数,这似乎误导了一些人。很显然的是,delete也需要知道对象的具体类型,才能将调用转交给该类型的自定义delete。有了delete的保证,自定义delete操作符并不需要检查它的参数类型。而且作为一个类型成员,它也不会不知道所属的类型。因此,自定义delete以void*为参数并不代表delete不需要类型信息。或许C++要求语法如此只是为了保证函数签名的一致?

假如我们要自己实现一个delete函数,这个函数只能是一个模板函数,就像std::_Destroy一样。

template<typename T>

void Delete(T* pObj) { pObj->~T(); free(pObj); }

对于开头处提到的ptr_fun(operator delete),这里delete并没有调用上下文,于是它退化成了一个类似void delete(void*)的函数。假若delete是一个模板函数,那么我们可以这么写:

ptr_fun(operator delete<CMyClass>)

但是很遗憾,没有这样的语法支持。

解决这个问题的唯一办法就是,写一个模板函数,接收模板类型的指针类型,然后在函数内部调用delete。这个模板函数可以传递给ptr_fun。有两点小要求:

1. 这个模板函数不能返回void,它必须有返回值,原因请看ptr_fun生成对象的operator()——该操作符会用目标函数的返回值来调用return。而编译器不支持return void这样的语法。

2. 模板函数必须在调用ptr_fun之前显式实例化,否则将无法链接成功。

class TypeA
{
public:
    ~TypeA() 
    {
        cout<<"destruct"<<endl;
    }
};

template<typename T>
int Delete(T* obj)
{
    delete obj;
    return 1;
}

template int Delete(TypeA*);

int mainPtrFunDelete()
{
    TypeA* obj = new TypeA();
    //std::ptr_fun(::delete<TypeA>)(obj);
    std::ptr_fun(Delete<TypeA>)(obj); 
    return 1;
}