46、动态存储类

动态存储类

StrVec Class Design

StrVec Class Definition

class StrVec
{
public:
    //构造函数
    StrVec():elements(nullptr), first_free(nullptr), cap(nullptr){}

    //用initializer_list<string>初始化参数列表
    StrVec(initializer_list<string> il):StrVec(il){}

    //拷贝构造函数
    StrVec(const StrVec&);
    //拷贝赋值运算符
    StrVec &operator=(const StrVec&);
    //析构函数
    ~StrVec();

    void push_back(const string&);  //拷贝元素进入队列
    size_t size() const {return first_free-elements;}   //队列存放元素个数
    size_t capacity() const {return cap-elements;}      //队列存储空间大小
    string* begin() const {return elements;}            //起始指针
    string* end() const {return first_free;}            //第一个为空的元素
    //。。。

private:
//    vector<string> vs;
    allocator<string> alloc;    //分配元素
    //判断是否要添加新的内存空间
    void chk_n_alloc()
    {
        if(size() == capacity())        //判断数据长度是否已经达到分配空间的上限
            reallocate();       //如果是,那么就重新分配空间
    }
    //用到拷贝构造函数,拷贝赋值运算符,析构函数的工具函数
    pair<string*, string*> alloc_n_copy(const string*, const string*);
    void free();        //销毁这个类的元素,并释放空间
    void reallocate();  //重新分配空间并且把原来的元素移动到新空间上

    string *elements;   //指向这个队列的第一个元素
    string *first_free; //指向这个队列第一个为空的元素,即最后元素的后一位
    string *cap;        //指向最后一个空间位置后一位
};

English explain:

? The default constructor (implicitly) default initializes alloc and (explicitly)

initializes the pointers to nullptr, indicating that there are no elements.

? The size member returns the number of elements actually in use, which is

equal to first_free - elements.

? The capacity member returns the number of elements that the StrVec can

hold, which is equal to cap - elements.

? The chk_n_alloc causes the StrVec to be reallocated when there is no room

to add another element, which happens when cap == first_free.

? The begin and end members return pointers to the first (i.e., elements) and

one past the last constructed element (i.e., first_free), respectively.

Using construct

void StrVec::push_back(const string& s)
{
    chk_n_alloc();      //检查看是否需要重新分配空间
    //吧元素s拷贝到first_free之后
    alloc.construct(first_free++, s);   //一个空间就是一个string大小
}

The alloc_n_copy Member

拷贝构造函数,拷贝赋值运算符,析构函数的工具函数

inline
pair<string*, string*>
StrVec::alloc_n_copy(const string* b, const  string* e) //开始和结尾指针
{
    //要拷贝对象要求的空间大小
    auto data=alloc.allocate(e-b);
    //吧b,e之间的元素拷贝到data中
    //返回一个pair
    pair<string*, string*> p={data, uninitialized_copy(b, e, data)};
    return p;
}

The free Member

void StrVec::free()
{
    //如果头指针本身就是空的,那么就不用释放内存了,因为就是空的
    if(elements)
    {
        //倒序,一个个的吧元素删除,内存释放
        for(auto p=first_free ; p != elements ; /* empty )
            alloc.destroy(--p);
        alloc.deallocate(elements, cap-elements);
/*
deallocate(p,n);         释放内存,
在类型为T*的指针p指向的地址,保存着n个对象,
运行deallocate之前调用destroy是用户的责任。
Once the elements have been destroyed, we free the space that this StrVec
allocated by calling deallocate */
    }
}

这里有一个错误演示,我也还没搞懂为什么报错,调了半天没出来,只要留在这里,以后解决了。

void StrVec::free()
{
    if(elements)
    {
        for_each(first_free, elements, [this](string* p){alloc.destroy(--p);});
        alloc.deallocate(elements, cap-first_free);
    }
}

Copy-Control Members

StrVec::StrVec(const StrVec &s)
{
    // call alloc_n_copy to allocate exactly as many elements as in s
    auto newdata=alloc_n_copy(s.begin(), s.end());  //pair类型
    elements=newdata.first;
    first_free=cap=newdata.second;
    //The return value from alloc_n_copy is a pair of pointers.

}

The destructor calls free:

inline
StrVec::~StrVec()
{
    free();
}

拷贝赋值运算符

StrVec &StrVec::operator=(const StrVec &rhs)
{
    //先把要赋值的值拷贝下来
    auto data=alloc_n_copy(rhs.begin(), rhs.end());
    free();     //吧右边的值销毁
    //重新赋予给左边
    elements=data.first;
    first_free=cap=data.second;

    return *this;
}

Moving, Not Copying, Elements during Reallocation

move在头文件utility里面

The reallocate Member

void StrVec::reallocate()
{
    //直接把当前容量扩充到2倍
    auto newcapacity=size() ? 2*size() : 1 ;
    //allocate新内存
    auto newdata=alloc.allocate(newcapacity);   //申请新空间
    //吧元素重老的地方移到新的地方
    auto dest=newdata;      //指出新空间第一个空位置
    auto elem=elements;     //老队列的第一个元素
    //全部构造到新的里面去
    for(size_t i=0 ; i != size() ; ++i)
        alloc.construct(dest++, std::move(*elem++));    //循环吧老的元素移动到新的上
    free();     //移完了,把老空间全部释放

    //重新更新数据指针
    elements=newdata;
    first_free=dest;
    cap=elements+newcapacity;
}

PS:不要问我,为什么你的英语突然变得那么厉害了!!!我是不会告诉你我的那本中文版的C++ primer被我搞掉了的!!!!

46、动态存储类

时间: 2024-08-25 20:28:40

46、动态存储类的相关文章

C++实现根据类名动态生成类对象

在开发后台服务的过程中,我们常常需要从数据库中取数据,并将数据缓存在本地中,另外,我们的服务还需要有更新数据的能力:包括定时的主动更新以及数据库数据更新时服务收到通知的被动更新. 之前在需要用到以上功能的时候,模仿着组内通用的数据Cache部分的代码来写,十分方便,基本上只需要自己写两个类:一个是取数据并缓存数据的类XXXData,一个是扇出数据的类XXXFetcher. 在需要使用数据的时候,通过: FetcherFactory::getFetcher<XXXFetcher>() 即可获取一

存储类、链接、内存管理

作用域:代码块作用域.函数原型作用域.文件作用域 函数作用域(只适用于goto) 链接:外部链接.内部链接.空链接(代码块作用域.函数原型作用域) 存储时期:静态存储时期.自动动态存储时期 五种存储类:自动,寄存器(代码块内使用register,不能使用地址运算符),外部链接的静态.内部链接的静态(static).空链接 x =30;while(x++<33){ int x = 100; printf("%d",x); } 打印了三次100,递增必须在条件判断语句中 对函数参量不

c语言中用户标识符的作用域和存储类(2)

2 局部变量及其作用域和生存期 2.1 auto变量 当在函数内部或复合语句内定义变量时,如果没有指定存储类,或使用auto说明符,系统默认所定义的变量为自动类别.因此: float a; 等价于 auto float a; auto变量的存储单元被分配在内存的动态存储区.当进入函数体时,系统自动为auto变量分配存储单元:退出时自动释放这些存储单元.这类局部变量的作用域是从定义的位置起,到函数体结束为止.由于函数的频繁调用,动态存储区内为某个变量分配的存储单元位置随程序的运行而改变,变量的初值

c语言中用户标识符的作用域和存储类(1)

在c语言中,标识符必须先定义后使用.但定义语句应该放在什么位置?在程序中,一个定义了的标识符是否随处可用?这些问题牵涉到标识符的作用域.经过赋值的变量是否在程序运行期间总能保存其值?这又牵涉到变量的生存期.当一个程序的若干函数分别存放于不同的文件中时又有何限制?对于上述问题,c语言中有具体的规定. 读者应该特别注意 “定义” 和 “说明” 这两个词.“定义”(definition)是指给变量分配确定的存储单元,“说明”(declaration)只是说明变量的性质,而并不分配存储空间. 1 局部变

黑马程序员___java动态代理类

----------- android培训.java培训.java学习型技术博客.期待与您交流! --------- 1.什么是动态代理? 答:动态代理可以提供对另一个对象的访问,同时隐藏实际对象的具体事实.代理一般会实现它所表示的实际对象的接口.代理可以访问实际对象,但是延迟实现实际对象的部分功能,实际对象实现系统的实际功能,代理对象对客户隐藏了实际对象.客户不知道它是与代理打交道还是与实际对象打交道.2.为什么使用动态代理? 答:因为动态代理可以对请求进行任何处理 3.使用它有哪些好处? 答

串的动态存储分配

串:由零个或者多个字符组成的有限序列.零个字符的串称为空串,和空格串[一个或多个空格诸城的串]有区别,请注意比较.在串的抽象数据类型中,有五个操作组成最小操作子集,分别是串赋值StrAssign,串比较StrCompare,求串长StrLength ,串联接Concat,求子串SubString.现以串的动态存储结构为例,将5个基本操作实现如下: 具体介绍详见注释. 1 /** 2 在串的抽象数据类型的13中操作中:串赋值StrAssign,串比较StrCompare,求串长StrLength

C++动态创建类的实例

写在前面:首先声明,C++实际上是不可以动态创建类的实例的. 下面简单做一个解释,所谓动态创建类的实例是指在程序运行过程中创建并使用一个“未知”的类.而“未知”是指在程序编译时并不知道有哪些类是需要动态创建的.对于C++这门语言来说,编译时不知道的类是不可以在运行时使用的.所以我说C++是不可以的. 不过C++可以做到另一件事情,基本可以满足大多数类似的需求. 我描述为通过类名称创建类的实例. 进入正题. 首先描述一下需求: 编写一个程序实现在程序运行过程中通过类名称(即字符串变量)创建该类的实

C 存储类

C 存储类 存储类定义 C 程序中变量/函数的范围(可见性)和生命周期.这些说明符放置在它们所修饰的类型之前.下面列出 C 程序中可用的存储类: auto register static extern auto 存储类 auto 存储类是所有局部变量默认的存储类. { int mount; auto int month; } 上面的实例定义了两个带有相同存储类的变量,auto 只能用在函数内,即 auto 只能修饰局部变量. register 存储类 register 存储类用于定义存储在寄存器

C语言的存储类

Auto  普通局部栈变量:是自动存储,限定变量只能在函数内部使用,这种对象会自动创建和销毁 ,建议这个变量要放在堆栈上面,调用函数时分配内存,函数结束时释放内存.一般隐藏auto默认为自动存储类别.我们程序都变量大多是自动变量. 实例 auto.c 1 #include <stdio.h> 2 3 int main(void) 4 { 5 auto int i = 9; /* 声明局部变量的关键字是 auto; 因可以省略, 几乎没人使用 */ 6 printf("%d\n&quo