std::vector的几种遍历方式与效率比较


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);

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)

很明显了,第二种方式是最快的

测试结果解析

个人觉得原因如下:

  1. 第一种方法每次都要调用size()函数去计算vec的长度。通过查看size(),其实现如下:
    指针地址相减,再来一个强制转换最后得到size()。就这这里稍微费点时间。
_LIBCPP_INLINE_VISIBILITY
size_type size() const_NOEXCEPT
{return static_cast<size_type>(this->__end_ -this->__begin_);}
  1. 第三种方式是最费时间的。使用迭代器it循环,迭代器本身不是内部数据,它的各种操作(比较,偏移,取值操作)都是一系列内联函数操作,暗地里干的事远比看到的复杂。这个迭代器给自己套上伪装,让你可以像使用指针一样利用它去访问对象,但是毕竟中间隔了一层。个人觉得迭代器的实用主要是便于stl中算法的实现,有一种通用的数据类型来访问各种容器中的元素。
  2. 第四种方式从形式上看非常简洁,可干活却没有长相利索。这是C++11的新特性。这篇博文中有详细介绍http://www.cnblogs.com/h46incon/archive/2013/06/02/3113737.html.
  3. 第五种方式也是c++的新特性。其中包括大受推崇的lambda特性。这种特性是向其它语言学习的结果。在这里也跑的不是最快的。

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

原文链接

https://blog.csdn.net/qq_35040828/article/details/82586728

标准模板库(STL)中的std::vector是一个动态数组容器,而std::string是一个字符串容器。要将std::vector转换为std::string,可以通过以下几种方法实现: 方法一: ```cpp std::vector<char>* data = response->getResponseData(); std::string res; const char* s = &(*data->begin()); res = std::string(s, data->size()); std::cout << res; ``` 在这种方法中,我们使用了std::string的构造函数,该构造函数接受一个指向字符数组的指针和字符数组的大小作为参数,并将其转换为std::string对象。然后,我们将结果打印到标准输出流(std::cout)中。 方法二: ```cpp std::vector<char>* data = response->getResponseData(); std::string res; res.insert(res.begin(), data->begin(), data->end()); std::cout << res; ``` 在这种方法中,我们使用了std::string的insert()函数,该函数接受一个迭代器范围作为参数,将指定范围内的元素插入到std::string的开头位置。这样就能够将std::vector中的字符转换为std::string对象。然后,我们将结果打印到标准输出流(std::cout)中。 方法三: ```cpp std::vector<char>* data = response->getResponseData(); std::string res; for (int i = 0; i < data->size(); i++) { res += (*data)[i]; } res += '\0'; std::cout << res; ``` 在这种方法中,我们使用了一个循环来遍历std::vector中的每个字符,并将其逐个添加到std::string对象中。最后,我们在std::string的末尾添加了一个空字符,以确保字符串的终止符。然后,我们将结果打印到标准输出流(std::cout)中。 总结起来,以上三种方法都可以将std::vector转换为std::string对象,具体选择哪种方法取决于具体的需求和代码实现的上下文。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [std::vector<char> * 转std::string 的三种方法](https://blog.csdn.net/hulefei29/article/details/84499030)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值