美文网首页
C++容器的遍历与程序的性能分析

C++容器的遍历与程序的性能分析

作者: 路长心自远 | 来源:发表于2022-07-22 09:45 被阅读0次

c++11之后,c++可能是受到java等语言的启发,引入了更多的遍历容器的方式,但是,如果使用方式不对,可能会导致程序的性能低下。本例就使用了多种遍历方式来访问list的元素。并演示了其中的区别。

这段代码演示了如下C++的特点

  1. 对list等容器的元素来遍历的时候,如果元素是非指针类型,使用迭代器的速度要比使用 for( auto ele:list_name) 的方式快。for( auto ele:list_name)的方式,ele是个临时变量,这种方式不能修改list_name中的元素本身。但是使用for( auto & ele:list_name)可以修改list_name中的元素本身,for( auto ele:list_name)的性能与迭代器的性能相当;
  2. 例子中计算性能的方式不太严谨,可以去掉每个循环中的循环体和增加循环次数来更加精确的演示速度的快慢。
  3. 如果list等容器的元素类型是非指针类型,使用一个变量名字去添加元素的时候,会在堆中产生临时变量,这些临时变量会放在容器中。
  4. 如果list等容器的元素类型是指针类型,使用迭代器和for( auto ele:list_name) 和 for( auto & ele:list_name) 的性能相当,因为遍历这些元素不会产生临时变量。
  5. 在析构对象的时候,堆中的对象,是先创建的先析构,栈中的对象析构顺序符合栈的特点:后创建的先析构,即“弹栈式”的析构。
  6. 本例使用了list容器,而没有使用vector,使用vector的话,如果元素是非指针类型,则vector本身创建的时候,就会有很多次的构造和析构,这是因为vector的元素的地址是连续的。一旦内存中的某个地址装不下当前的元素的时候,系统会去寻找更大的地址来装更多的元素,这个地址的改变就要涉及到对象的复制构造和析构。而list则没有这个缺点,它是“链表式”的保存元素。
  7. 如果追求性能,需要使用list,且元素类型须是指针类型。
// g++ -std=c++11 list_for.cpp -o list_for

#include <iostream>
#include <string>
#include <list>
#include <chrono>

#define STD_COUT std::cout<<__FILE__<<":"<<__LINE__<<"@"<<__FUNCTION__<<"\t"

class ClassA
{
public:
    ClassA()
    {
        STD_COUT <<this<<" default constructor"<<std::endl;
        m_iNum = 0;
    }

    ClassA(const ClassA & a)
    {
        STD_COUT <<this<<" copy constructor 1"<< std::endl;
        this->m_iNum = a.m_iNum;
        this->str_msg_ = a.str_msg_;
    }

    ClassA operator = (const ClassA & a){
        STD_COUT <<this<<" copy constructor 2"<<std::endl;
        this->m_iNum = a.m_iNum;
        this->str_msg_ = a.str_msg_;
        return *this;
    }

    virtual ~ClassA()
    {
        STD_COUT <<this<< std::endl;
        m_iNum = 0;
    }

    virtual void showMsg()
    {
        STD_COUT << "from ClassA " <<this<< std::endl;
    }

    virtual void callMsg()
    {
        this->showMsg();
    }

public:
    int m_iNum;
    std::string str_msg_;
};

int main(int argc, char ** argv){
    std::cout <<"=============在栈中创建一个对象================= "<<(void*)&main << std::endl;
    ClassA class_a1;
    
    std::list<ClassA> myList2;
    for(int i =0; i< 5;i++){
        if(class_a1.str_msg_.length() < 2000){
            class_a1.str_msg_.append("this is s string");
        }
        class_a1.m_iNum = i;
        std::cout <<"=============加入一个元素,这里会产生复制构造出临时变量放到list中================="<< std::endl;
        myList2.push_back(class_a1);
    }

    // 当前微秒
    long long micro_seconds1 = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
    std::cout <<"当前微秒\t"<< micro_seconds1 << std::endl;

    for(std::list<ClassA>::iterator itr = myList2.begin(); itr != myList2.end() ; itr++){
        std::cout <<"元素中的地址 "<<(void*)&(*itr)<< std::endl;
    }

    long long micro_seconds2 = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
    std::cout <<"当前微秒\t"<< micro_seconds2 << " 使用迭代器的时间差 "<<micro_seconds2-micro_seconds1 << std::endl;

    micro_seconds1 = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
    std::cout <<"当前微秒\t"<< micro_seconds1 << std::endl;


    for(auto ele: myList2){
        std::cout <<"元素中的地址 "<<(void*)&(ele)<< std::endl;
    }

    micro_seconds2 = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
    std::cout <<"当前微秒\t"<< micro_seconds2 << " 使用 auto 的时间差 "<<micro_seconds2-micro_seconds1 << std::endl;

    micro_seconds1 = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
    std::cout <<"当前微秒\t"<< micro_seconds1 << std::endl;


    for(auto & ele: myList2){
        std::cout <<"元素中的地址 "<<(void*)&(ele)<< std::endl;
    }

    micro_seconds2 = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
    std::cout <<"当前微秒\t"<< micro_seconds2 << " 使用 auto & 的时间差 "<<micro_seconds2-micro_seconds1 << std::endl;

    std::cout <<"=============在堆中创建一个对象=================" << std::endl;
    std::list<ClassA*> myList;
    for(int i =0; i< 5;i++){
        ClassA* class_a2 = new ClassA();
        if(class_a2->str_msg_.length() < 2000){
            class_a2->str_msg_.append("this is s string");
        }
        class_a2->m_iNum = i;

        myList.push_back(class_a2);
    }

    // 当前微秒
    micro_seconds1 = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
    std::cout <<"当前微秒\t"<< micro_seconds1 << std::endl;

    for(std::list<ClassA*>::iterator itr = myList.begin(); itr != myList.end() ; itr++){
        std::cout <<"元素中的地址 "<<(void*)&(*itr)<< std::endl;
    }

    micro_seconds2 = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
    std::cout <<"当前微秒\t"<< micro_seconds2 << " 使用迭代器的时间差 "<<micro_seconds2-micro_seconds1 << std::endl;

    micro_seconds1 = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
    std::cout <<"当前微秒\t"<< micro_seconds1 << std::endl;


    for(auto ele: myList){
        std::cout <<"元素中的地址 "<<(void*)&(ele)<< std::endl;
    }

    micro_seconds2 = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
    std::cout <<"当前微秒\t"<< micro_seconds2 << " 使用 auto 的时间差 "<<micro_seconds2-micro_seconds1 << std::endl;

    micro_seconds1 = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
    std::cout <<"当前微秒\t"<< micro_seconds1 << std::endl;


    for(auto & ele: myList){
        std::cout <<"元素中的地址 "<<(void*)&(ele)<< std::endl;
    }

    micro_seconds2 = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
    std::cout <<"当前微秒\t"<< micro_seconds2 << " 使用 auto & 的时间差 "<<micro_seconds2-micro_seconds1 << std::endl;

    std::cout <<"=============手动析构堆中的变量=================" << std::endl;
    for(auto & ele: myList){
        delete ele;
    }
    std::cout <<"=============程序结束,自动析构栈中的变量=================" << std::endl;
    return 0;
}

输出结果略。

相关文章

  • C++容器的遍历与程序的性能分析

    c++11之后,c++可能是受到java等语言的启发,引入了更多的遍历容器的方式,但是,如果使用方式不对,可能会导...

  • C++性能分析工具gperftools

    C++性能分析工具gperftools 最近编写的程序遇到了性能瓶颈,CPU吃满的情况下消费能力上不去,导致消息积...

  • 【java容器的刻意练习】【十五】ArrayDeque的性能分析

    这篇我们来看看ArrayDeque的性能分析。 之前我们在《【八】ArrayList与LinkedList的遍历》...

  • 内存池

    参考资料 C++内存池介绍与经典内存池的实现 C++ 应用程序性能优化,第 6 章:内存池 linux c++ 内...

  • HashMap 的 7 种遍历方式与性能分析!(强烈推荐)

    HashMap 的 7 种遍历方式与性能分析!(强烈推荐)随着 JDK 1.8 Streams API 的发布,使...

  • 性能测试流程与调优

    性能测试流程与调优 概述 分析性能需求 制定性能测试计划 设计场景 编写脚本和程序初始化配置 执行性能测试 分析结...

  • STL学习笔记之容器篇

    容器 条款1:仔细选择你的容器 C++提供了很多可供程序员使用的容器:(1) 标准STL序列容器:vector,...

  • 容器简单介绍

    c++中经常会用到各种容器,需要对容器的数据结构或者算法有基本理解,在适当的时候以选用适当的容器,以增强性能 容器...

  • Boolan C++ 第六周 容器

    《C++ primer》中所提的评价容器性能的主要两个方面: 向容器添加或删除元素的代价 非顺序访问容器中元素的代...

  • Java程序优化

    Java程序优化 参考书籍: Java程序性能优化 让你的Java程序更快、更稳定.pdf 性能分析-程序性能指...

网友评论

      本文标题:C++容器的遍历与程序的性能分析

      本文链接:https://www.haomeiwen.com/subject/vplmirtx.html