容器(vector)、数组、new创建的动态数组,你到底用哪一个(执行效率分析)
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创建的动态数组,你到底用哪一个(执行效率分析)的更多相关文章
- 学习日记--用Vector(向量)实现动态数组
Vector的使用方法: 能在添加元素时增加长度的数组称为动态数组或可变长数组.相对地,必须事先指定长度,只能容纳一定数量元素的数组称为静态数组.下面分享一下如何借助STL(标准模板库)中的Vecto ...
- 分配一维动态数组or 二维动态数组的方法以及学习 new 方法or vector
先来个开胃菜 // 使用new动态分配存储空间 #include<iostream> using std::cout; int main() { // 第1种方式 int *a=new i ...
- 用最复杂的方式学会数组(Python实现动态数组)
Python序列类型 在本博客中,我们将学习探讨Python的各种"序列"类,内置的三大常用数据结构--列表类(list).元组类(tuple)和字符串类(str). 不知道你发现 ...
- [UE4]动态数组:TArray容器
为什么使用UE4提供的容器类? 如果你用过C++的STL库,你就知道STL提供了各种各样的容器/数据结构,使得你对处理很多数据的时候非常快捷高效.UE4同样也提供了类似的库,库里面的类型是以T开头的, ...
- 数据结构(1) 第一天 算法时间复杂度、线性表介绍、动态数组搭建(仿Vector)、单向链表搭建、企业链表思路
01 数据结构基本概念_大O表示法 无论n是多少都执行三个具体步骤 执行了12步 O(12)=>O(1) O(n) log 2 N = log c N / log c N (相当于两个对数进行了 ...
- 动态数组 - vector
#include <iostream> #include <vector> // 头文件 using namespace std; int main() { vector< ...
- c++动态数组的优点,创建和删除
动态数组可以有两种使用方式: 1:不能预先知道数组的大小使用动态数组 传统数组(静态数组)是需要在程序运行前,就指定大小,比如说 int i = 10; int a[i]; 这种就是不合法的. 因为函 ...
- 线性表之顺序存储结构(C语言动态数组实现)
线性表的定义:N个数据元素的有限序列 线性表从存储结构上分为:顺序存储结构(数组)和 链式存储结构(链表) 顺序存储结构:是用一段连续的内存空间存储表中的数据 L=(a1,a2,a3....an) 链 ...
- C++中关于[]静态数组和new分配的动态数组的区别分析
这篇文章主要介绍了C++中关于[]静态数组和new分配的动态数组的区别分析,很重要的概念,需要的朋友可以参考下 本文以实例分析了C++语言中关于[]静态数组和new分配的动态数组的区别,可以帮助大家加 ...
随机推荐
- docker和docker compose常用操作命令
首先区分一下docker中几个概念 Image:镜像,相当于一个root文件系统,不包含任何动态数据 Container:容器,镜像运行时的实体,实质是进程,容器进程运行于属于自己的独立的命名空间 d ...
- haproxy + keepalived 实现高可用负载均衡集群
1. 首先准备两台tomcat机器,作为集群的单点server. 第一台: 1)tomcat,需要Java的支持,所以同样要安装Java环境. 安装非常简单. tar xf jdk-7u65-lin ...
- POJ2553 汇点个数(强连通分量
The Bottom of a Graph Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 12070 Accepted: ...
- 003---生成器 & 迭代器
生成器 & 迭代器 列表生成式 现在有个需求,列表[1, 2, 3, 4, 5, 6, 7, 8, 9],将列表里的每个值加1. 二逼青年版 a = [1, 2, 3, 4, 5, 6, 7, ...
- Python3爬虫(十) 数据存储之非关系型数据库MongoDB
Infi-chu: http://www.cnblogs.com/Infi-chu/ 一.非关系型数据库NoSQL全程是Not Only SQL,非关系型数据库.NoSQL是基于键值对的,不需要经过S ...
- ABAP CDS ON HANA-(10)項目結合して一つ項目として表示
Numeric Functions ABS(arg) CEIL(arg) DIV(arg1, arg2) DIVISION(arg1, arg2, dec) FLOOR(arg) MOD(arg1, ...
- HBase import tsv,csv File
一,HBase中创建table 表(liupeng:test)并创建 info ,contect 列簇 hbase(main):258:0> create "liupeng:Test& ...
- C#的委托Delegate
一.委托基础 1.什么是委托 委托(Delegate) 是存有对某个方法的引用的一种引用类型变量,用关键字delegate申明,实现相同返回值和参数的函数的动态调用,提供了对方法的抽象. 委托(Del ...
- 一步一步构建手机WebApp开发——页面布局篇
继上一篇:一步一步构建手机WebApp开发——环境搭建篇过后,我相信很多朋友都想看看实战案例,这一次的教程是页面布局篇,先上图: 如上图所示,此篇教程便是教初学者如何快速布局这样的页面.废话少说,直接 ...
- Android之线程安全的单例模式,Adapter注意事项之引用传值
线程安全的单例模式单位模式一般写法如下: public static FestivalLab mInstance; private FestivalLab() { } public static Fe ...