前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++学习笔记-分配器,基础学习

C++学习笔记-分配器,基础学习

原创
作者头像
买唯送忧
修改2021-05-06 18:13:20
5090
修改2021-05-06 18:13:20
举报
文章被收录于专栏:虚拟技术学习

一、allocator必要接口

代码语言:javascript
复制
/*
 * allocator::value_type
 * allocator::pointer
 * allocator::const_pointer
 * allocator::reference
 * allocator::const_reference
 * allocator::size_type
 * allocator::difference_type
 * allocator::rebind:一个嵌套的class template, 拥有唯一成员other
 * allocator::allocator():默认构造函数
 * allocator::allocator(const allocator&):拷贝构造
 * allocator::~allocator()
 * pointer allocator::address(reference x) 返回某个对象的地址,相当于&x
 * const_pointer allocator::address(const_reference x)  返回某个const对象的地址
 * pointer allocator::allocate(size_type n, const void* = 0) 配置空间,n个T空间,第二个是提示,可以依靠它来增加额外空间,或者忽略
 * void allocator::deallocate(pointer p, size_type n) 归还先前的配置空间
 * size_type alloctor::max_size() const 返回可配置的最大量
 * void allocator::construct(pointer p, const T& x) 等同于;new(p) T(x)
 * void alloctor::destory(pointer p) 等同于p-> ~T
 */

二、用以上接口编写一个分配器

代码语言:javascript
复制
//通过以上接口编写一个自己的分配器
#include <new>  //for placement new
#include <cstddef> //for ptrdiff_t, size_t
#include <cstdlib> //for exit()
#include <climits> // for UINT_MAX
#include <iostream>

namespace  yxAlloc{
    template<class T>
    inline T* _allocate(ptrdiff_t size, T*)
    {
        set_new_handler(0);//检测内存是否足
        T* tmp = (T*)(::operator new((size_t)(size * sizeof (T))));
        if (0 == tmp)
        {
            std::cerr << "out of memory" << std::endl;
            exit(1);
        }
        return tmp;
    }
    template <class T>
    inline void _deallocate(T* p)
    {
        ::operator delete(p);
    }
    template<class T1, class T2>
    void _construct(T1* p, const T2& x)
    {
        new(p) T1(x);
    }

    template <class T>
    void _destory(T* p)
    {
        p->~T();
    }

    template<class T>
    class allocator{
    public:
        typedef T           value_type;
        typedef T*          pointer;
        typedef T&          reference;
        typedef const T*    const_pointer;
        typedef const T&    const_reference;
        typedef ptrdiff_t   difference_type;
        typedef size_t      size_type;
//        template<class U>
        struct rebind{
            typedef allocator<int> other;
        };
        pointer allocate(size_type n, const void* hint = nullptr)
        {
            return _allocate(static_cast<difference_type>(n), static_cast<pointer>(hint));
        }

        void deallocate(pointer p, size_type n)
        {
            _deallocate(p);
        }

        void construct(pointer p, const T& t)
        {
            _construct(p, t);
        }

        void destory(pointer p)
        {
            _destory(p);
        }

        size_type max_size() const {return (size_type)UINT_MAX/sizeof(T);}

        pointer address(reference x)
        {
            return (pointer)&x;
        }
        const_pointer address(const_reference x)
        {
            return (const_pointer)&x;
        }

    };
}

//当然以上自己编写的分配器只能在VC, BC下使用,,,无法用在gcc中,因为sgi stl根本上脱离了stl

三、分析

1、allocate函数

(1)参数一

它是要生成的对应对象空间的个数,比如size * sizeof(T):生成size个T对象的空间;size类型一般为ptrdiff_t,一般用于定义两个指针的距离,,因为两个指针的加减,结果已经不再是指针,而是一种距离的概念,,因此C++引入ptrdiff_t的概念,相当于long int , size_t 可以理解为 long long unsigned int....。

(2)参数二:

第二个参数可有可无,需要增加空间的时候,可能会用到它,比如:const void* hint = 0;

(3)函数体分析

set_new_handler(0)一般用于处理内存是否够;该分配器用operator new()函数进行分配空间,实质上就是使用malloc进行分配(我之前的new,delete文章有说明),因此会额外给它两个cookie空间,从而会浪费空间。

2、deallocate函数

(1)参数一

就是之前已经配置空间的地址,

(2)参数二

(3)函数体分析

使用::operator delete函数进行空间的回收,实质上就是使用free.

3、construct函数

void_construct(T1* p,const T2& x){new(p)T1(x);}

这里使用的是placement new(所谓placement new就是在用户指定的内存位置上构建新的对象,这个构建过程不需要额外分配内存,只需要调用对象的构造函数即可。)比如上面的代码就调用T1::T1(x);(placement new是怎么做的呢,说白了就是把原本new做的两步工作分开来。第一步你自己分配内存,第二步你调用类的构造函数在自己分配的内存上构建新的对象。)

new(p)T1(x):就是在指针p的构建了一个T1的新的对象。可以节省空间,但是这就必须要显式调用析构函数所以就有了下面的函数

4、destory函数

p->~T();,当然还有第二版本的,要判断trivial destuctor,我还没学到。

四、基础学习

1、列表初始化

代码语言:javascript
复制
//即用{}进行数值初始化,要类型一致
double a = {1.23}   //对
double b = {1} //对
double c = 1.2;
int d = {1.22}  //错
//而不用花括号
int d = 1.22 //对,但是d = 1;
int d = (1.22) //对,但是d = 1;     

2、默认初始化

如果定义变量时没有指定初值,则变量被默认初始化(default initialized),此时变量被赋予了“默认值”。默认值到底是什么由变量类型决定,同时定义变量的位置也会对此有影响。如果是内置类型的变量未被显式初始化,它的值由定义的位置决定。定义于任何函数之外的变量初始化为0;定义于函数体内的内置类型的对象如果没有初始化,则其值未定义。类的对象如果没有显式地初始化,则其值由类确定。

3、变量声明和定义的关系

代码语言:javascript
复制
extern int i; //声明了i并未定义
int i ;       //声明并且定义了i;
extern int i = 1; //定义了
//在函数体内部,如果试图初始化一个由extern关键字标记的变量,将引发错误。
//声明和定义的区别看起来也许微不足道,但实际上却非常重要。如果要在多个文件中使用同一个变量,
//就必须将声明和定义分离。此时,变量的定义必须出现在且只能出现在一个文件中,
//而其他用到该变量的文件必须对其进行声明,却绝对不能重复定义。

#include <iostream>
int reuse = 32;
int main()
{
    int reuse = 0; //新建reuse,覆盖了全局reuse
    cout << reuse << endl; //0
    cout << ::reuse << endl; //32 强制全局
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、allocator必要接口
  • 二、用以上接口编写一个分配器
  • 三、分析
    • 1、allocate函数
      • (1)参数一
      • (2)参数二:
      • (3)函数体分析
    • 2、deallocate函数
      • (1)参数一
      • (2)参数二
      • (3)函数体分析
    • 3、construct函数
      • 4、destory函数
      • 四、基础学习
        • 1、列表初始化
          • 2、默认初始化
            • 3、变量声明和定义的关系
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档