第12章动态内存——allocator类

new和delete的两部分操作:内存分配(释放)对象构造(析构)

当分配一大块内存时,我们计划在这块内存上按需构造对象,在此情况下希望内存分配和对象构造分离。这表示:我们可以分配大块内存,但是只有真正需要时才执行对象创建操作(同时付出一定开销)

将内存分配和对象构造组合在一起可能会导致不必要的浪费

string *const p = new string[n]; 
string s = "aaa";
*p =s;
  • new表达式分配并且初始化了n个string,但是实际我们可能并不会用到n个string,造成了浪费。
  • 对于要使用的对象,在初始化之后立即赋予了新值,每个元素被赋值两次:一次在默认初始化,之后是在赋值。

 更重要的是,没有默认构造函数的类就不能动态分配数组(???不太理解)

allocator类

头文件:memory

作用:帮助我们将内存分配和对象构造分离开。提供一种类型感知的内存分配方法,分配的内存是原始的、未构造的。

类似于vector,allocator是一个模板。必须指明allocator可以分配的对象类型。

allocate()

分配一段内存,保存n个类型

allocator<string> alloc; //可以分配string的allocator对象
auto const p = alloc.allocate(n);//分配n个未初始化的string

这个allocator调用为n个string分配了内存

allocator分配未构造的内存

allocator分配未构造的内存(unconstructed),需要按需构造对象。

construct()

一个指针,表示在指定位置开始构造

零个(多个)额外参数,用来初始化构造的对象

    auto q = p; //q指向最后构造的元素之后的位置
    alloc.construct(q++);//*q为空字符串
    alloc.construct(q++,10,'c');//*q为cccccccccc
    alloc.construct(q++,"hi");

还未构造对象的情况下就使用原始内存是错误的!

cout<<*p<<endl;//正确:使用string的输出运算符
cout<<*q<<endl;//灾难:q指向未构造的内存!

WARNING:为了使用allocate返回的内存,必须使用construct构造对象,使用未构造的内存,其行为是未定义的。

对于每个构造的元素必须使用destroy来销毁它们

destroy()

接受一个指针,对指向对象执行析构函数

while(q!=p)
    alloc.destroy(--q);//释放我们真正构造的string

WARNING:我们只能对真正构造了的元素进行destroy操作。

一旦元素被销毁后,就可以重新使用这部分内存来保存其他string,也可以归还给系统,释放内存通过deallocate来完成:

alloca.deallocate(p,n);

deallocate()

第一个参数指针:指向allocate分配的内存;

第二个参数大小参数,必须与调用allocatee分配的大小一致。

拷贝和填充未初始化内存的算法

allocator类定义了两个伴随算法,在未初始化内存中创建对象。

NOTE:假设b,e是两个指针,并且p是一块内存,uninttialized_copy()表示在p这块内存,创建b到e区间的所有元素。

auto p = alloc.allocate(vi.size() * 2);
uninttialized_copy(b,e,p);

//分配比vi中元素所占用空间大一倍的动态内存
auto p = alloc.allocate(vi.size() * 2);
//通过拷贝vi的元素来构造从p开始的元素
auto q = uninttialized_copy(vi.begin(),vi.end(),p);
//将剩余的元素初始化为42
uninitialized_fill_n(q,vi.size(),42);

传递给uninitialized_cpy的目的地址迭代器必须指向未构造的内存,与copy不同,uninitialized_copy在给定目的位置构造元素

类似copy,uninitialized_copy返回(递增后的)目的位置迭代器,uninitialized_copy调用会返回一个指针,指向最后一个构造的元素之后的位置。

猜你喜欢

转载自blog.csdn.net/qq_34269988/article/details/88683018
今日推荐