1.问题的提出

在没有了解vector之前,动态数组一般都是又new创建的。在了解vector后发现vector竟是那样方便好用,但方便的同时却是以牺牲执行效率为代价的。网上对vector和array的评价和吐槽,也是喜忧参半,各有不同啊。在面临选择的时候,我们到底用哪一种呢,我们可能都犹豫过?下面对该问题进行理论分析和实际测试验证。

2.理论分析

2.1预备知识-程序的内存分配

一个由C/C++编译的程序占用的内存分为以下几个部分

       1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。是一种线性结构,其操作方式类似于数据结构中的栈,操作速度较快。但程序员是无法控制。

       2 、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,是一种链式结构,分配方式倒是类似于链表,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。

        3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放 

        4、文字常量区—常量字符串就是放在这里的。 程序结束后由系统释放

        5、程序代码区—存放函数体的二进制代码。

其中栈和堆构成了动态数据区:

├———————┤低端内存区域 

│ …… │ 

├———————┤ 

│ 动态数据区 │ 

├———————┤ 

│ …… │ 

├———————┤ 

│ 代码区 │ 

├———————┤ 

│ 静态数据区 │ 

├———————┤ 

│ …… │ 

├———————┤高端内存区域

以上堆和栈的分析参考博客1,关于堆和栈的区别与联系更详细的分析,请点击博客1

2.2数组、动态数组和vector的讨论如下:

回到本文的主题,数组是底层数据类型,存放在栈中,其内存的分配和释放完全由系统自动完成,效率最高;动态数组是程序员由new运算符创建的,存放在堆中,需由delete运算符人工释放,否则会内存泄露;vector,存放在堆中,由STL库中程序负责内存的分配和释放,使用方便。

关于vector的分析,参考STL源码剖析(P119-vector的内存管理)和C++primer(第四版9.4vector容器的自增长),vector的构造和内存管理如图1所示。如果容器中已经没有空间容纳新的元素,此时,由于元素必须连续存储以便索引访问,所以不能在内存中随便找个地方存储这个新元素。于是,vector 必须重新分配存储空间,用来存放原来的元素以及新添加的元素:存放在旧存储空间中的元素被复制到新存储空间里,接着插入新元素,最后撤销旧的存储空间。这是vector效率低的主要原因。

注意所谓的动态自增加,并不是在原空间之后接续新空间(因为无法保证原空间之后尚有可供配置的空间),而是以原大小的两倍另外配置一块大空间,然后将原内容拷贝过来,然后才开始在原内容之后构造新元素,并释放原空间。因此,对vector的任何操作,一旦引起空间重新配置,指向原vector的所有迭代器就都失效了。注意size和capacity的区别,size指容器当前拥有的元素个数,capacity指容器在必须分配新存储空间之前可以存储的元素总数,capacity总是大于或等于size的。

图1(来自STL源码剖析,图4-2)

3.数组、动态数组、vector的测试

对vector、预先reverse的vector、数组、new创建的动态数组测试代码如下:

vector的测试代码:

		DWORD start=GetTickCount();
int t=100;
int n=200000;
while (t)
{
vector<int> a,b;
for (int i=0;i<n;i++)
a.push_back(i);
t--;
}
cout<<"Runing time of program:"<<GetTickCount()-start<<endl;

预先reverse的vector的测试代码:

		 start=GetTickCount();
t=100;
n=200000;
while (t)
{
vector<int> a,b;
b.reserve(n+1);
for (int i=0;i<n;i++)
b.push_back(i);
t--;
}
cout<<"Runing time of program:"<<GetTickCount()-start<<endl;

数组的测试代码:

		 start=GetTickCount();
t=100;
n=200000;
while (t)
{
int a[200000];
for (int i=0;i<n;i++)
a[i]=i;
t--;
}
cout<<"Runing time of program:"<<GetTickCount()-start<<endl;

new创建的动态数组:

		 start=GetTickCount();
t=100;
n=200000;
while (t)
{
int *p=new int[n+1];
for (int i=0;i<n;i++)
p[i]=i;
delete []p;
t--;
}
cout<<"Runing time of program:"<<GetTickCount()-start<<endl;

运行结果为:

运行结果从上到下依次为,vector,预先reverse的vector、数组和动态数组的以上代码的执行时间(单位ms),从中可以看出,数组的执行效率是vector的10倍左右。执行效率不在同一个数量级,虽然容器操作简单方便。其效率排序依次是数组>动态数组>预先reverse的vector>vector。总之,数组和容器各有千秋,若硬件速度够快,对时间要求不那么高,用容器方便,也未尝不可。关键看你,看中什么,是效率还是方便。

容器(vector)、数组、new创建的动态数组,你到底用哪一个(执行效率分析)的更多相关文章

  1. 学习日记--用Vector(向量)实现动态数组

    Vector的使用方法: 能在添加元素时增加长度的数组称为动态数组或可变长数组.相对地,必须事先指定长度,只能容纳一定数量元素的数组称为静态数组.下面分享一下如何借助STL(标准模板库)中的Vecto ...

  2. 分配一维动态数组or 二维动态数组的方法以及学习 new 方法or vector

    先来个开胃菜 // 使用new动态分配存储空间 #include<iostream> using std::cout; int main() { // 第1种方式 int *a=new i ...

  3. 用最复杂的方式学会数组(Python实现动态数组)

    Python序列类型 在本博客中,我们将学习探讨Python的各种"序列"类,内置的三大常用数据结构--列表类(list).元组类(tuple)和字符串类(str). 不知道你发现 ...

  4. [UE4]动态数组:TArray容器

    为什么使用UE4提供的容器类? 如果你用过C++的STL库,你就知道STL提供了各种各样的容器/数据结构,使得你对处理很多数据的时候非常快捷高效.UE4同样也提供了类似的库,库里面的类型是以T开头的, ...

  5. 数据结构(1) 第一天 算法时间复杂度、线性表介绍、动态数组搭建(仿Vector)、单向链表搭建、企业链表思路

    01 数据结构基本概念_大O表示法 无论n是多少都执行三个具体步骤 执行了12步 O(12)=>O(1) O(n) log 2 N = log c N / log c N (相当于两个对数进行了 ...

  6. 动态数组 - vector

    #include <iostream> #include <vector> // 头文件 using namespace std; int main() { vector< ...

  7. c++动态数组的优点,创建和删除

    动态数组可以有两种使用方式: 1:不能预先知道数组的大小使用动态数组 传统数组(静态数组)是需要在程序运行前,就指定大小,比如说 int i = 10; int a[i]; 这种就是不合法的. 因为函 ...

  8. 线性表之顺序存储结构(C语言动态数组实现)

    线性表的定义:N个数据元素的有限序列 线性表从存储结构上分为:顺序存储结构(数组)和 链式存储结构(链表) 顺序存储结构:是用一段连续的内存空间存储表中的数据 L=(a1,a2,a3....an) 链 ...

  9. C++中关于[]静态数组和new分配的动态数组的区别分析

    这篇文章主要介绍了C++中关于[]静态数组和new分配的动态数组的区别分析,很重要的概念,需要的朋友可以参考下 本文以实例分析了C++语言中关于[]静态数组和new分配的动态数组的区别,可以帮助大家加 ...

随机推荐

  1. docker API 配置与使用

    在网上看到一大堆乱乱七八招的博客,很多都不能用,我根据这些天踩的坑来总结一下吧 首先!怎么配置 docker API 两种方法 在/etc/sysconfig/docker文件里加一行OPTIONS= ...

  2. android发布帖子类技术

    最近练习一些关于发布帖子的技术,说来也简单,就学了一点皮毛吧!好了,下面就上代码吧! 首先设计服务器的访问类,大家都知道现在东西都要联网的嘛! JSONParser的类: public class J ...

  3. grunt in webstorm

    1.install grunt sudo npm install -g grunt-cli npm install grunt --save-dev

  4. java程序——从命令行接收多个数字,求和之后输出结果

    命令行参数都是字符串,必须先将其转化为数字,才能相加.以下是流程图,源代码和输出结果. 流程图: 源代码: import java.util.Scanner; public class Test { ...

  5. struts2官方 中文教程 系列十:Form标签

    介绍 在本教程中,我们将探索其他Struts 2表单控件.在前面的教程中,我们介绍了如何使用Struts 2表单(处理表单.表单验证和消息资源文件),我们介绍了如何使用Struts 2 head, f ...

  6. KMP python实现

    首先去 https://blog.csdn.net/starstar1992/article/details/54913261/ 这里看下思想: 然后代码实现,一定要多调试几遍方能看懂: def ge ...

  7. CC3100BoosterPack和CC31XXEMUBOOST板子的测试

    1. 先测试右边的CC3100BoosterPack,测试发现LDO坏了,无法输出3.3V,所以只能用左边的板子供电. 2. 插上CC31XXEMUBOOST板子的J1,两个板子插在一起,等待驱动安装 ...

  8. 【C#】 语法糖

    [C#] 语法糖 一, 扩展方法 1. 对某个类功能上的扩展 2. 特点: 使用方便,可以在不修改原代码的基础上进行扩展. 参照 linq,linq 就是一系列的扩展方法 3. 语法: 非泛型静态类, ...

  9. facebook hash key

    private void printHashKey() { try { PackageInfo info = getPackageManager().getPackageInfo( "xxx ...

  10. 常用模块(xml)

    XML(可扩展性标记语言)是一种非常常用的文件类型,主要用于存储和传输数据.在编程中,对XML的操作也非常常见. 本文根据python库文档中的xml.etree.ElementTree类来进行介绍X ...