看智能指针的时候遇到一组函数蛮有意思的,即 checked_delete(T* x) 和 checked_array_delete(T* x),这两个函数的作用是安全删除参数所指向的变量或数组。

template<class T> inline void checked_delete(T* x)
{  typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];  (void) sizeof(type_must_be_complete);  delete x;
}  template<class T> inline void checked_array_delete(T* x)
{  typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];  (void) sizeof(type_must_be_complete);  delete[] x;
}  

函数只有最后一行不同,分别调用了 delete 和 delete[] 操作符,顺便说一句,在 C/C++ 中指针既可以指向一个变量,也可以指向一个数组,因此这两个函数仅仅从参数无法区别出来待删除的是单个变量还是数组,只能由调用者自行保证调用了正确的函数。

函数总共三行语句,第三行是根本目的,很容易理解,前两行的目的就是为了所谓的安全性了。怎么个安全法呢?这两个函数是函数模版,在编译时无法确定参数的类型,而动态运行时的错误是比较棘手的,所以用这行代码:

typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];  

来将运行时错误转变为编译期错误。这句话其实就是定义了一个固定大小的 char 型数组,数组名为 type_must_be_complete,数组大小是多少呢?是 sizeof(T)?1:-1, ?:这个三元操作符大家都很熟悉了,若 sizeof(T) 非 0,这个表达式的值为 1,即 typedef 了一个大小为 1 的 char 型数组,否则定义一个大小为 -1 的数组。数组大小还能为负数?当然不能,于是就会报错,而且是编译期错误,于是就将一个动态运行时错误在编译时就发现了。

接下来解释 sizeof 什么时候返回 0。 C/C++ 语言本身似乎没有这种情况,但有些编译器会作一些扩展,比如 GCC 对于 incomplete type 使用sizeof时,会返回 0。那什么又叫做 incomplete type 呢,就是那些声明了,但没有定义的类型,例如:

class A;  extern A a;  

C++ 标准允许通过一个 delete 表达式删除指向不完全类的指针。如果该类有一个非平凡的析构函数,或者有一个类相关的 delete 操作符,那么其行为就是无定义的。因此编译器作了这种扩展,以将这种未定义的行为转为编译期错误,帮助程序员们及早发现。

函数的第二行语句的作用据说是为了防止编译器优化,因为编译器检测到typedef的类型未被使用到的话可能就会将其优化掉,因而第二行语句使用了这个类型,告诉编译器这个 typedef 是有用的,不能优化掉。至于 (void) 强制类型转换,问了同学,说是为了消除编译器对未使用 sizeof 返回值的警告。

仅仅几行代码都有这么多讲究,要学的东西还很多啊。错误和疏漏的地方欢迎批评指正!

转载于:https://blog.csdn.net/encoder1234/article/details/79012336

(SAW:Game Over!)

Cpp / checked_delete 原理相关推荐

  1. C/CPP 编译原理 硬件相关

    1.static修饰局部变量和全局变量会有什么效果 解题思路 静态全局变量:具有全局作用域,它与全局变量的区别在于如果程序包含多个文件的话,它作用于定义它的文件里,不能作用到其它文件里,即被 stat ...

  2. 基于QT的网络嗅探器实现(网络安全课程设计)

    在这学期的网络安全课程设计中,我们需要自己实现一个基于WinPcap编程接口的网络嗅探器,历时两周完成,主要参考资料: 1.WinPcap 中文技术文档(http://www.ferrisxu.com ...

  3. `QStyle`自定义重绘`QSlider`控件

    简介: 根据QStyle的继承关系和重绘原理:通过实现一个继承QCommonStyle类的实现,实现自己的自定义控件QSlider控件. 文章目录 本博文的简述or解决问题? 系列博文: 运行效果: ...

  4. qt-opencv图像分割之Otsu算法实例

    qt-opencv图像分割之Otsu算法实例 1 .pro项目文件配置 2 ui设计 3 代码 3.1 mainwindow.h 3.2 mainwindow.cpp 4 运行结果 4.1 打开图片 ...

  5. (转载)虚幻引擎3--13掌握虚幻技术UnrealScript 接口

    第十三章 – 接口 什么是接口? 接口示例 USB 电脑鼠标 电源插座 编程说明 定义接口 声明和定义 接口继承 实现接口 为什么使用接口? 结束语 指南 13.1 – 指南针, 第一部分:指南针接口 ...

  6. 结对编程——一路忘川

    结对编程--一路忘川 一.项目信息 项目 内容 这个作业属于哪个课程 2023 年北航软件工程 这个作业的要求在哪里 结对项目-最长英语单词链 教学班级 周四下午班 项目地址 项目地址 我在这个课程的 ...

  7. Cpp / std::move 原理

    零.功能和源码 std::move 是一个类型转换器,将左值转换成右值,其实现如下: template <typename T> typename remove_reference< ...

  8. Cpp 对象模型探索 / 多重继承下基类指针释放子类对象的原理说明(虚析构函数的作用)

    源码 #include <iostream>class Base1 { public:virtual void func_1_1(){ std::cout << "B ...

  9. Cpp 对象模型探索 / 对象访问成员变量的原理

    一.栗子 1.源码 #include <iostream> #include <stdio.h>class Base { public:Base() { std::cout & ...

最新文章

  1. 复旦陈静静 | 把握当下,坚持热爱,与食物图像识别结缘的科研之路
  2. WPF入门:数据绑定
  3. 怎么计算一组数据的波动_数据分析(一):数据描述统计
  4. 【Android 安装包优化】资源混淆 ( 资源混淆效果 | APK 构建流程简介 | 资源 ID 组成 )
  5. Linux解决openoffice转换PDF乱码问题(ubutun16.0.4)
  6. lisp用entmake生产圆柱体_使用lisp语言实现在平面图中自动画出桥梁的墩柱标识.doc...
  7. 微信小程序循环不同列表实现动态点击隐藏
  8. 多线程启动定时器 会等待上一次执行完成?_Java多线程
  9. 【Matplotlib】详解图像各个部分
  10. 如何从0开始开源项目参与_如何开始一个开源项目
  11. Linux系统学习之 三:新手必须掌握的Linux命令3
  12. Java中基于TCP通过socket嵌套字连接方式传送文件
  13. OFD文件在线阅读器
  14. Scratch案例——弹球游戏
  15. 计算机未来的发展趋势和现状,计算机发展现状跟未来发展趋势.docx
  16. cad工具箱详细讲解_CAD的工具说明及使用讲解
  17. 第149篇 笔记-web3
  18. Frida-Dexdump 脱壳工具下载使用以及相关技术介绍
  19. 超文本传输协议版本 2 [http/2 spec]
  20. python批量检索文献_快解锁新姿势,教你如何用Python搞定文献搜索和科研图片!...

热门文章

  1. 简单扩展shiro 实现NOT、AND、OR权限验证(支持复杂一点的表达式)
  2. C#综合揭秘——细说多线程(上)
  3. RHEL 5服务篇—使用Apache搭建Web服务(一)
  4. SpringCloud教程- 断路器(Hystrix)(SpringCloud版本Finchley)
  5. postgresql介绍,安装,启动
  6. Linux脚本:xjps查看各个节点java进程
  7. Linux debian/deepin安装apache2(httpd)服务:文件服务器搭建
  8. 配置CentOS 7阿里云镜像源
  9. 【完整代码】Scala akka入门示例
  10. Scala集合常用方法:fold折叠