动态数组new、allocate

来源:互联网 发布:检查语法错误的软件 编辑:程序博客网 时间:2024/05/18 00:54
  • new和delete运算符一次分配/释放一个对象,但某些应用需要一次为很多对象分配内存的功能
  • C++提供了两种一次分配一个对象数组的方法
  • new表达式语法,可以分配并初始化一个对象数组
  • allocate类可以将分配和初始化分离
  • 涉及到分配动态数组的类必须定义自己版本的操作,在拷贝、复制以及销毁对象时管理所关联的内存

new和数组

  • 要在类型名后跟一对方括号,其中指明要分配的对象的数目
  • 下例中new分配要求数量的对象,假如分配成功,并返回指向的第一个对象的指针
int *pia = new int[get_size()];//pia指向第一个int
  • 可以使用类型别名表示数组类型来分配一个数组,这样new表达式中不需要方括号
typedef int arrT[42];//arrT表示42个int的数组类型int *p = new arrt;//p指向第一个int
  • 上述代码中编译器执行的形式是int *p = new int[42]

分配一个数组会得到一个元素类型的指针

  • 用new分配的数组时,并未得到一个数组类型的对象,而是一个数组元素类型的指针
  • 由于分配的内存不是一个数组类型,一次不能对动态数组调用begin或end。这些函数使用数组维度来返回指向首元素和尾后元素的指针

初始化动态分配对象的数组

  • new分配的对象,不管是单个分配的还是数组中的,都是默认初始化的
  • 可以对数组中的元素进行值初始化,方法是在大小之后跟一对空括号
int *pia1 = new int[10]; //10个未初始化的intint *pia2 = new int[10](); //10个值初始化为0的intstring *pia3 = new string[10]; //10个空的stringstring *pia4 = new string[10](); //10个空的string
  • 新标准中可以用元素初始化器的花括号列表
int *pia = new int[10]{0,1,2,3,4,5,6,7};//剩下元素使用值初始化

动态分配一个空数组是合法的

  • 不能创建一个大小为0的静态数组对象,但是当调用new[0]时时合法的:
char arr[0];//错误:不能定义长度为零的数组char* arr = new char[0];//正确,但arr不能解引用,因为它不指向任何元素

释放动态数组

  • 在指针前加上一个空方括号对:
delete p;//p指向一个动态分配的对象或为空delete []pa;//pa必须为一个动态分配的数组或空
  • 第二条语句销毁pa指向的数组中的元素,并释放对应内存
  • 数组中元素按照逆序销毁
  • 空方括号对只是编译器此指针指向一个对象数组的第一个元素
  • 对于使用类型别名定义的数组类型,在new表达式中不使用[],但是销毁时也必须使用方括号
typedef int arrT[42];//arrT表示42个int的数组类型int *p = new arrt;//p指向第一个intdelete []p;

智能指针和动态数组

  • 标准库提供了一个可以管理new分配的数组的unique_ptr版本:
unique_ptr<int[]> up(new int[10]);//up指向一个包含10个未初始化int的数组up.releasr();//自动用delete[]销毁其指针
  • 类型说明符中的[]说明up是一个指向一个int数组而不是一个int,由于up指向一个数组,当up销毁它管理的指针时,自动使用delete[ ]
  • 当unique_ptr指向一个数组时,可以使用下标运算符来访问数组的元素
for(size_t i =o;i != 10; ++i){    up[i] = i;}
  • share_ptr不能直接指向动态数组,需要提供自己定义的删除器
  • share_ptr不直接支持动态数组的下标运算,其访问元素可以先获得内置指针
for(size_t i =o;i != 10; ++i){    *(sp.get()+i) = i;}

allocate类

  • new有一些灵活性上的局限,其中一方面表现在它将内存分配和对象构造结合在一起
  • 当分配大块内存时,我们计划在这块内存上按需构造对象,我们需要将内存分配和对象构造分离
  • 那些没有默认构造函数的类不能用new动态分配数组

allocate类

  • allocate类在头文件memory中,其将内存分配和对像构造分离开
  • 提供一种类型感知的内存分配方法,其分配的内存是原始的,未构造的
  • aloocator是一个模板,当一个allocator对象分配内存时,其根据给定对象类型确定恰当的内存大小和对其位置
allocate<string> alloc; //可以分配string的allocator对象auto const p = alloc.allocate(n); //分配n个未初始化的string

allocator<T> a

  • 定义名为a的allocator对象,它可以为类型为T的对象分配内存

a.allocate(n)

  • 分配一段原始的、未构造的内存,保存n个类型为T的对象

a.deallocate(p,n)

  • 释放从T*指针p中地址开始的内存,这块内存保存了n个类型为T的对象
  • p必须是一个先前有allocate返回的指针,且n必须是p创建时所要求的大小
  • 在调用deallocate前,用户必须对每个在这块内存中创建的对象调用destroy

a.construct(p,args)

  • p必须为一个类型为T*的指针,指向一块原始内存
  • args被传递给类型为T的构造函数,用来在p指向的内存中构造一个对象

a.destroy(p)

p为T*类型的指针,此算法对p指向的对象执行析构函数

allocator分配为构造的内存

  • allocator分配的内存时未构造的,我们需要再次内存中构造对象
  • construct函数接受一个指针和零个或多个额外参数,在指定位置构造一个函数
  • 在未未构造对象的情况下使用原始内存是错误的
  • 当用完对象后,要对每个构造的对象用destroy函数销毁他们
  • 我们只能对真正构造了的元素进行destroy
  • 一旦元素被销毁,可以重新使用这块内存保存其它的T
  • 也可以将内存归还给系统,释放内存通过调用deallocate来完成

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

  • 标准库为allocator类定义了两个伴随算法,在未初始化的内存中创建对象,它们都定义在memory头文件中
  • 这些函数在给定目的位置创建元素,而不是由系统分配内存给他们
  • 返回一个指针,指向最后一个构造元素之后的位置

uninitialized_copy(b,e,b2)

  • 从迭代器b和e指出的输入范围中拷贝元素到迭代器b2指定的未构造原始内存中
  • b2指向的内存必须足够大,能容纳输入序列中元素的拷贝

    uninitialized_copy(b,n,b2)

  • 从迭代器b指向的元素开始,拷贝n个元素到b2开始的内存中

uninitialized_fill(b,e,t)

  • 从迭代器b和e指定的原始内存范围中创建对象,对象的值均为t的拷贝

uninitialized_fill(b,n,t)

  • 从迭代器b指向的内存开始创建n个对象,b必须指向足够大的未构造的原始内存,能够容纳给定数量的对象
0 0
原创粉丝点击