std::vector是我在标准库中实用最频繁的容器。总结一下在遍历和创建vector时需要注意的一些地方。

在不考虑线程安全问题的前提下,在C++11中有五种遍历方式。

方式一

for (size_t i =0; i < vec.size(); i ++) {

int d = vec[i];

}

方式二

size_t len = vec.size();

for (size_t i =0; i < len; i ++) {

int d = vec[i];

}

方式三

for (auto it = vec.begin(); it != vec.end(); it ++) {

int d = *it;

}

方式四

for (int i:vec) {

int d = i;

}

方式五

for_each(vec.begin(), vec.end(), [](int i){

int d = i;

});

代码很简单,如果不实际测试的话。你能推测出哪种方式效率最高吗?

我在mac下面用xcode测试了这五种遍历方式。

////h文件

void testBianli();

void testBianli1(conststd::vector<int>& vec);

void testBianli2(conststd::vector<int>& vec);

void testBianli3(conststd::vector<int>& vec);

void testBianli4(const std::vector<int>& vec);

void testBianli5(const std::vector<int>& vec);

////end h文件

///cpp文件

void testBianli()

{

size_t counter = 1000000;

std::vector<int> vec(counter);

testBianli1(vec);

testBianli2(vec);

testBianli3(vec);

testBianli4(vec);

testBianli5(vec);

}

void  testBianli1(conststd::vector<int>& vec)

{

MEARSURE_DURATION(all);

for (size_t i =0; i < vec.size(); i ++) {

int d = vec[i];

}

}

void  testBianli2(conststd::vector<int>& vec)

{

MEARSURE_DURATION(all);

size_t len = vec.size();

for (size_t i =0; i < len; i ++) {

int d = vec[i];

}

}

void testBianli3(conststd::vector<int>& vec)

{

MEARSURE_DURATION(all);

for (auto it = vec.begin(); it != vec.end(); it ++) {

int d = *it;

}

}

void testBianli4(conststd::vector<int>& vec)

{

MEARSURE_DURATION(all);

for (int i:vec) {

int d = i;

}

}

void testBianli5(conststd::vector<int>& vec)

{

MEARSURE_DURATION(all);

for_each(vec.begin(), vec.end(), [](int i){

int d = i;

});

}

其中需要定义一个测试函数运行时间的类和一个宏

#define MEARSURE_DURATION(fun) CFunctionDuration fun(std::string(std::string(__FUNCTION__) +" "+std::string(#fun)).c_str() );

class CFunctionDuration {

public:

CFunctionDuration(const char* funname)

{

m_start_df = clock();

sprintf(m_funname,"%s",funname);

}

~CFunctionDuration()

{

double du = (clock() -m_start_df)*0.001;

if (du >= 0) {

printf("%s running duration:%f(ms) \n",m_funname,du);

}

}

private:

double m_start_df;

char m_funname[256];

};

最后输出结果如下:

testBianli1 all running duration:3.440000(ms) 

testBianli2 all running duration:2.854000(ms) 

testBianli3 all running duration:11.009000(ms) 

testBianli4 all running duration:5.109000(ms) 

testBianli5 all running duration:7.637000(ms)

很明显了,第二种方式是最快的。个人觉得原因如下:

第一种方法每次都要调用size()函数去计算vec的长度。通过查看size(),其实现如下:

_LIBCPP_INLINE_VISIBILITY

size_type size() const_NOEXCEPT

{return static_cast<size_type>(this->__end_ -this->__begin_);}

指针地址相减,再来一个强制转换最后得到size()。就这这里稍微费点时间。

第三种方式是最费时间的。使用迭代器it循环,迭代器本身不是内部数据,它的各种操作(比较,偏移,取值操作)都是一系列内联函数操作,暗地里干的事远比看到的复杂。这个迭代器给自己套上伪装,让你可以像使用指针一样利用它去访问对象,但是毕竟中间隔了一层。个人觉得迭代器的实用主要是便于stl中算法的实现,有一种通用的数据类型来访问各种容器中的元素。

第四种方式从形式上看非常简洁,可干活却没有长相利索。这是C++11的新特性。这篇博文中有详细介绍http://www.cnblogs.com/h46incon/archive/2013/06/02/3113737.html.

第五种方式也是c++的新特性。其中包括大受推崇的lambda特性。这种特性是向其它语言学习的结果。在这里也跑的不是最快的。

其实这些运行时间结果的差别也只有在遍历过程中对元素操作的过程很简短的时候才会显现出来。当对每个元素操作花费的时间跟纯粹遍历vector所费时间不是一个数量级时,这些区别就不重要了。另外这个时间在不同设备上运行的时间肯定是不一样的。不同编译器下得到的结果也不一样,但是其相对运行效率还是有参考意义的。

std::vector遍历的更多相关文章

  1. C++ Arrays, std::array, std::vector 总结

    原文来自: https://shendrick.net/Coding%20Tips/2015/03/15/cpparrayvsvector.html @Seth Hendrick Original a ...

  2. c++转载系列 std::vector模板库用法介绍

    来源:http://blog.csdn.net/phoebin/article/details/3864590 介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作 ...

  3. C++ 中的std::vector介绍(转)

    vector是C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库.vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单地说,vec ...

  4. std::vector介绍

    vector是C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库.vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单地说,vec ...

  5. std::vector<Channel2*> m_allChannels;容器,以及如何根据channelid的意义

    std::vector<Channel2*> m_allChannels;容器,以及如何根据channelid的意义 这个容器保存了所有客户端连接的channel Channel2* Li ...

  6. std::vector数据复制

    std::vector<boost::shared_ptr <ITEM> > srcItemList;  // 数据源 std::vector<ITEM>  des ...

  7. 单独删除std::vector <std::vector<string> > 的所有元素

    下面为测试代码: 1.创建 std::vector< std::vector<string> > vc2; 2.初始化 std::vector<string> vc ...

  8. std::vector的分片拷贝和插入

    一般我们在用Qt的QByteArrary或者List的时候,会有相应的append的方法,该函数,就是把数据加入末尾.但是std::vector就没有相应的方法.但是我们可以用insert方法来实现: ...

  9. 使用std::vector优化点云动画显示一例

    1. 准备 使用std::vector应该知道几点: (1)内存连续的容器,有点像数组 (2)与std::list相比,插入和删除元素比较慢- 因为数据迁移 (3)添加元素可能会引发内存分配和数据迁移 ...

随机推荐

  1. 安全简单解决MVC 提示 检测到有潜在危险的 Request.Form 值.

    一般使用富文本编辑器的时候.提交的表单中包含HTML字符,就会出现此错误提示. 使用 ValidateInput(false) 特性标签并不能解决此问题. 网上前篇一律的回答是修改Web.Config ...

  2. Redis源代码分析(三十)--- pubsub公布订阅模式

    今天学习了Redis中比較高大上的名词,"公布订阅模式".公布订阅模式这个词在我最開始接触听说的时候是在JMS(Java Message Service)java消息服务中听说的. ...

  3. 推断给定的IP地址是否是内网IP

    /** * 推断给定的IP地址是否是内网IP * * @author GaoHuanJie */ public class Test{ public boolean isInnerIP(String ...

  4. 【详细】【转】C#中理解委托和事件 事件的本质其实就是委托 RabbitMQ英汉互翼(一),RabbitMQ, RabbitMQ教程, RabbitMQ入门

    [详细][转]C#中理解委托和事件   文章是很基础,但很实用,看了这篇文章,让我一下回到了2016年刚刚学委托的时候,故转之! 1.委托 委托类似于C++中的函数指针(一个指向内存位置的指针).委托 ...

  5. LeetCode 645. Set Mismatch (集合不匹配)

    The set S originally contains numbers from 1 to n. But unfortunately, due to the data error, one of ...

  6. Date类型转换为Integer类型

    Date类型转换为Integer类型: Integer date = Integer.valueOf(String.valueOf(new SimpleDateFormat("yyyyMMd ...

  7. swift 学习笔记一

    看 Developing IOS 8 Apps with swift 的时候看到一些比較实用的点,记录一下: 1.将函数作为參数传递. 比如: 写一个两个数求和的函数:performOperation ...

  8. Excel 常用快捷键键 快捷方式

    移动整行的位置 Shift + Alt + 鼠标拖拽 不加Shit + Alt 移动后 留白 注意:需要移动鼠标到行的最上面,变成十字箭头

  9. B1297 [SCOI2009]迷路 矩阵

    这个题我觉得很有必要写一篇博客.首先,我们需要知道,假如一个邻接矩阵只有0/1构成,那么它自己的n次方就是走n步之后的方案数.但这个题还有2~9咋办呢.我们观察发现,这个题只有10个点,而且边权< ...

  10. Linux必知必会的目录结构

    1.目录结构 /bin 二进制文件 命令 /sbin 超级命令 只有root用户可以使用 /boot 系统的引导文件 系统内核 /dev 设备文件 光盘 硬盘分区 /etc 系统配置文件 /home ...