以下是这两个函数的整体示意图:

    

  construct()和destroy()函数必须被设计为全局函数,STL规定空间配置器必须包含这两个成员函数,但是std::alloc的配置器并没有遵循这一规则。

  以下是包含在<stl_construct.h>头文件中的两个函数的的定义:

  

/* NOTE: This is an internal header file, included by other STL headers.*   You should not attempt to use it directly.*/#ifndef __SGI_STL_INTERNAL_CONSTRUCT_H
#define __SGI_STL_INTERNAL_CONSTRUCT_H#include <new.h>__STL_BEGIN_NAMESPACE// construct and destroy.  These functions are not part of the C++ standard,
// and are provided for backward compatibility with the HP STL.  We also
// provide internal names _Construct and _Destroy that can be used within
// the library, so that standard-conforming pieces don't have to rely on
// non-standard extensions.// Internal names

template <class _T1, class _T2>
inline void _Construct(_T1* __p, const _T2& __value)
{new ((void*) __p) _T1(__value);
}template <class _T1>
inline void _Construct(_T1* __p)
{new ((void*) __p) _T1();
}//第一版本,接受一个指针,好说,直接调用析构函数全部析构
template <class _Tp>
inline void _Destroy(_Tp* __pointer)
{__pointer->~_Tp();
}//以下是destroy()第二版本,接受两个迭代器,只删除一部分值,该函数设法找出元素的数值型别,进而利用__type_traits<>求取最适当措施
template <class _ForwardIterator>
inline void _Destroy(_ForwardIterator __first, _ForwardIterator __last) {__destroy(__first, __last, __VALUE_TYPE(__first));
}//判断元素的数值型别(value_type)是否有trivial destructor
template <class _ForwardIterator, class _Tp>
inline void
__destroy(_ForwardIterator __first, _ForwardIterator __last, _Tp*)
{typedef typename __type_traits<_Tp>::has_trivial_destructor_Trivial_destructor;__destroy_aux(__first, __last, _Trivial_destructor());
}//如果元素型别为non-trivial destructor(有意义),逐一删除元素
template <class _ForwardIterator>
void
__destroy_aux(_ForwardIterator __first, _ForwardIterator __last, __false_type)
{for ( ; __first != __last; ++__first)destroy(&*__first);
}//如果元素型别为trivial destructor(无伤大雅),什么也不做
template <class _ForwardIterator>
inline void __destroy_aux(_ForwardIterator, _ForwardIterator, __true_type) {}inline void _Destroy(char*, char*) {}
inline void _Destroy(int*, int*) {}
inline void _Destroy(long*, long*) {}
inline void _Destroy(float*, float*) {}
inline void _Destroy(double*, double*) {}
#ifdef __STL_HAS_WCHAR_T
inline void _Destroy(wchar_t*, wchar_t*) {}
#endif /* __STL_HAS_WCHAR_T */// --------------------------------------------------
// Old names from the HP STL.
//HP STL以前旧的函数命名
template <class _T1, class _T2>
inline void construct(_T1* __p, const _T2& __value)
{_Construct(__p, __value);
}template <class _T1>
inline void construct(_T1* __p)
{_Construct(__p);
}template <class _Tp>
inline void destroy(_Tp* __pointer){_Destroy(__pointer);
}template <class _ForwardIterator>
inline void destroy(_ForwardIterator __first, _ForwardIterator __last){_Destroy(__first, __last);
}__STL_END_NAMESPACE#endif /* __SGI_STL_INTERNAL_CONSTRUCT_H */// Local Variables:
// mode:C++
// End:

  上述 _Construct(_T1* __p, const _T2& __value), 接受一个指针__p和一个初值__value,该函数的用途是将初值设定到指针所指的空间上,通过C++的placement new 运算子来完成。

  destory()有两个版本,第一个版本接受一个指针,意思是要释放掉该指针所指的内存,直接调用析构函数就行,第二个版本接受 first 和 last 两个迭代器,意思是析构掉[first, last)范围内的所有对象,这里存在一个型别判断问题,当范围特别大时,而每个对象的析构函数都是trivial destructor(无关痛痒),那么一次次调用这样的析构函数实际上是对效率的一种伤害,因此就应该先利用value_type()判断迭代器所指对象的型别,再利用type_traits<T>判断该型别的析构函数是否真的无关痛痒,是的话(__true_type),则什么也不做就结束,若不是(__false_type),那就通过循环的方式遍历整个范围一一调用destroy()函数进行析构。

  以前的C++98并不支持对 “指针所指之物” 的型别判断,也不支持 “对象析构函数是否为trivial” 的判断,现在的C++11新特性有个decltype,可以获取指针所指之物的型别,至于判断__type_traits<>,则需要另外设定对象的特性萃取方案,好在SGI STL里面有一道关于traits编程技法的私房菜,后面再写博客介绍。

转载于:https://www.cnblogs.com/Forever-Road/p/6800582.html

STL初探——构造和析构的基本工具: construct()和destroy()相关推荐

  1. C++ STL : 空间配置器——构造和析构的基本工具construct和destroy

    文章目录 构造和析构的基本工具 1.construct 2. destroy 2.1普通版本 2.2 类型萃取版本 源代码 构造和析构的基本工具 1.construct 对placement new包 ...

  2. 自己动手实现STL 02:构造析构的基本工具construct()和destroy()(stl_construct.h)

    一.前言 上一篇,我先完成了对内存配置器的实现.然而后面在内存上的算法还依赖于两个全局函数,construct()和destroy(),前者负责在指定的内存上调用对象的构造函数,在内存上构造出对象.后 ...

  3. 【设计原则和建议】 构造和析构对象

    良好的构造和析构对象,控制对象生命周期可以较大的提高程序的性能,降低GC的压力,减少BUG几率. 本文还是比较简单的,主要还是经验的总结,很多东西也许各位已经知道,也许不知道.希望大家一起讨论. 1. ...

  4. 声明及赋值_重述《Effective C++》二——构造、析构、赋值运算

    关于本专栏,请看为什么写这个专栏.如果你想阅读带有条款目录的文章,欢迎访问我的主页. 构造和析构一方面是对象的诞生和终结:另一方面,它们也意味着资源的开辟和归还.这些操作犯错误会导致深远的后果--你需 ...

  5. 【No.7 C++对象的构造与析构时间】

    ==[注意]== 程序语言只是我们与计算机交流并让计算机实现我们创造性思想的工具,可以并鼓励深入掌握一门语言,但千万别沉迷于钻某种语言的牛角尖,一定要把握好二者间的度 本帖属不定时连载贴,以试卷的形式 ...

  6. 【C++深度剖析教程25】继承中的构造与析构

    今天来学习C++中继承的构造与析构,有兴趣一起学习的加qq:1126137994 1.问题 如何初始化父类成员?父类构造函数与子类构造函数有什么关系? 子类对象是如何构造的? 子类中可以定义构造函数 ...

  7. STL源码剖析 内存基本处理工具 初始化空间的五个函数

    初始化空间的五个函数 构造函数 construct() 析构函数 destroy() 剩余三个底层函数 和 高层函数之间的对应关系如下 uninitialized_copy()  对应 copy() ...

  8. c/c++入门教程 - 2.4.6 继承、公共继承、保护继承、私有继承、virtual虚继承(概念、语法、方式、构造和析构顺序、同名成员处理、继承同名静态成员处理、多继承语法、菱形继承、钻石继承)

    目录 4.6 继承 4.6.1 继承的基本语法 4.6.2 继承方式 4.6.3 继承中的对象模型 4.6.4 继承中构造和析构顺序 4.6.5 继承同名成员处理方式 4.6.6 继承同名静态成员处理 ...

  9. php构造和析构方法,php5构造函数与析构函数实例

    自php5起,有了构造函数与析构函数. 这使得php更富有面向对象的魅力了. 在php4时,构造函数用的是与类同名的函数来进行构造这个动作. 例如: 复制代码 代码示例: /* * myclass.p ...

最新文章

  1. CRT exCRT模板
  2. lstm结构图_神经网络——单层LSTM
  3. Linux 系统中的权限管理
  4. 数据库的缓存管理[ASPNET2.0深入挖掘系列听后感]
  5. 对现有的所能找到的DDOS代码(攻击模块)做出一次分析----自定义攻击篇
  6. unbantu上python安装步骤_如何在Ubuntu中安装Python 3.6?
  7. IntelliJ IDEA for Mac 项目窗口详解(Project Windows)
  8. java truevfs_Java-Apache Commons VFS:使用FTP
  9. 资深码农:拿下软件测试,只需掌握好这两种方法!
  10. 动态阈值_如何设置数据看板(大屏)数据异常报警的动态阈值
  11. 不用sqrt实现平方根_如何在R中使用sqrt()查找平方根?
  12. AJAX核心对象-- XMLHttpRequest 对象使用详解 (一)
  13. if 标准体重 的计算
  14. linux中的ul命令,Linux ngrep 命令用法详解-Linux命令大全(手册)
  15. 处理System.IO.Ports未能找到类型或命名空间名
  16. Pytorch 中的 forward理解
  17. Auto.js 找图 找色 剪切图片 坐标区域计算方法
  18. QCC3040---Glossary
  19. w10计算机运行特别卡,win10会很卡,详细教您怎么解决
  20. 以太坊2.0迁移之际,会有哪些机会和挑战?| Sodium线上发布会

热门文章

  1. mysql查看防火墙状态命令_Linux设置允许指定端口通过防火墙centos7
  2. 内核电源管理器已启动关机转换_Linux系统启动流程
  3. dataframe 提取月数据_pandas dataframe数据提取的方法
  4. 使用proxy来调用未定义的属性方法
  5. linux双网卡驱动配置,linux网卡驱动安装、双网卡绑定
  6. 逸仙电商企业网络推广如何打造出百亿完美日记后又收购高端护肤品牌
  7. 网络营销专员浅析在网络营销推广中有不少渠道可适当“利用”一下
  8. Java树形转扁平_多层嵌套map对象转扁平化map
  9. 开发日记-20190512 关键词 Dagger2原理
  10. B+树索引和哈希索引的区别——我在想全文搜索引擎为啥不用hash索引而非得使用B+呢?...