前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【C++11】 改进程序性能的方法--emplace_back和无序容器

【C++11】 改进程序性能的方法--emplace_back和无序容器

作者头像
CPP开发前沿
发布2021-11-16 14:04:05
6980
发布2021-11-16 14:04:05
举报
文章被收录于专栏:CPP开发前沿CPP开发前沿

C++11在性能上做了很大的改进,最大程度的减少了内存移动和拷贝,除了前面说的右值引用外,还有下面两个:

  • empalce系列函数通过直接构造对象的方式避免内存拷贝和移动;
  • 无序容器在插入元素时不排序,提升了插入效率,但是如果关键字是自定义的需要提供hash函数和比较函数

1 emplace系列函数

在C++11之前,向vector中插入数据时常用的方法是push_back,从C++11开始,又提供了empalce,emplace_back方法,这些方法可以看成是push_back的替代品,不但使用简单,而且性能提升也比较明显。emplace_back的使用方法如下:

代码语言:javascript
复制
struct A
{
int x;
double y;
    A(int a,double b):x(a),y(b){}
};  
int main()
{  
std::vector<A> v;
    v.emplace_back(1,2);
std::cout<<v.size()<<std::endl;
return 0;
}

从上面的代码可以看出,emplace_back方法使用简单,可以直接通过构造函数构造对象,因此,在实际编码的时候,我们也需要提供对象的构造方法,如果不提供,编译时将会报错,可以注释掉构造函数验证下。

相比push_back,emplace_back的性能优势也很明显,emplace_back通过减少内存移动和拷贝从而提升容器的插入性能,可以在上面的代码基础上改造完成。

代码语言:javascript
复制
struct A  
{
int x;
double y;
std::string z;
    A(int a,double b,std::string c):x(a),y(b),z(c) {
std::cout<<"is constructed"<<std::endl;
    }
    A(const A &otherA):x(otherA.x),y(otherA.y),z(std::move(otherA.z)){
std::cout<<"is moved"<<std::endl;
    }
};  
int main()
{  
std::vector<A> v;
std::cout<<"------emplace_back:---------"<<std::endl;
    v.emplace_back(1,2,"helloword");
std::cout<<"------push_back:---------"<<std::endl;
    v.push_back(A(3,4,"china"));
return 0;
}

运行结果如下:

代码语言:javascript
复制
------emplace_back:---------
is constructed
------push_back:---------
is constructed
is moved
is moved

从结果可以看出,在对vector的插入过程中,push_back方法构造了一次,移动了两次;使用emplace_back只进行了一次构造,没有进行内存的移动。

综上可以看出,在实际的应用中应该使用emplace系列函数代替传统的push_back等相关函数,但也需要注意一点,如果类或者结构体中没有提供构造函数,那么就不能使用emplace系列函数进行替换。

2 无序容器

C++11中新增了无序容器,如:unordered_map/unordered_multimap和unordered_set/unordered_multiset容器,在实际插入时,这些容器不在进行排序,因此相对有序的map和set来说效率都有提升。

map和set的底层实现是红黑树,对应的无序容器底层实现是Hash Table,由于内部通过哈希进行快速操作因此效率将会更高。在使用无序容器时,如果是基本类型数据,则不需要提供哈希函数和比较函数,使用方法和普通的map、set是一样的,如果数据类型是自定义的,在使用时需要提供哈希函数和比较函数,具体代码如下:

代码语言:javascript
复制
struct Key  
{
std::string first;
std::string second;
};  
struct KeyHash{
std::size_t operator() (const Key &k) const{
return std::hash<std::string>() (k.first)^
        (std::hash<std::string>() (k.second) << 1);
    }
};
struct KeyEqual{
bool operator()(const Key &lhs,const Key &rhs) const {
return lhs.first==rhs.first && lhs.second == rhs.second ;
    }
};
int main()
{  
//定义一个空的无序map 
std::unordered_map<std::string,std::string> mymap1;
//初始化
std::unordered_map<std::string,double> mymap2 = {
     {"mom",5.4},
     {"dad",6.1},
     {"bro",5.9} };
//拷贝构造
std::unordered_map<std::string,double> mymap3 = mymap2;
//移动构造
std::unordered_map<std::string,double> mymap4 = std::move(mymap2);
//区间构造
std::vector<std::pair<std::string,double> > v = {
         {"cpp",1},
         {"java",2}
     };
std::unordered_map<std::string,double> mymap5(v.begin(),v.end());
std::unordered_map<std::string,double> mymap7(mymap2.begin(),mymap2.end());
//自定义无序容器
std::unordered_map< Key,std::string,KeyHash,KeyEqual> mymap6={
         { {"cpp","top"},"one"},
         { {"java","top"},"two"}
     };
return 0;
}

从上面的代码可以看出,无序容器的用法和有序容器在使用上基本没有什么区别。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-09-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 CPP开发前沿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档