vector的性能利器reserve

转载请注明文章出处:https://tlanyan.me/reserve-of... vector是C++编程时的常用容器,其帮助用户自动管理存储空间,简单易用,且能避免资源泄露的问题。需要动态分配存储空间的场景,完全可替代原生数组。 vector被人诟病的地方在于性能。C++ 11引入array容器,有原生数组的性能,编译期能确定大小的情况可取代vector。但对于运行期才能确定大小的情况,array不适用,还是得上vector。 实践中提高vector性能的要点是尽量使用reserve(仅次于换编译器和STL实现)。运行期依然不能确定数组的个数,明智的选择是什么也不做,push_back/emplace_back就足够;运行期能确定个数,则应该用reserve,不建议用传递大小的数组构造函数或者调用resize。 reserve vs resizereserve和resize函数都能分配足够容纳下指定个数对象的空间。不同之处是resize(或构造函数传递数组个数)会改变数组的size(即当前元素的指针),并且极大的可能性会调用存储对象的(复制)构造函数。reserve做的事情就比较纯粹:仅分配所需的空间。 一段代码说明三者的区别: // file: test.cpp#include <iostream>#include <vector>class Foo { public: Foo() { std::cout << "Foo constructor" << std::endl; }};int main(int argc, char* argv[]) { std::cout << "initialize vector with element number..." << std::endl; std::vector<Foo> vec1(5); std::cout << "-------------" << std::endl; std::cout << "vec1 size:" << vec1.size() << std::endl << std::endl; std::cout << "vector resize..." << std::endl; std::vector<Foo> vec2; vec2.resize(5); std::cout << "-------------" << std::endl; std::cout << "vec2 size:" << vec2.size() << std::endl << std::endl; std::cout << "vector reserve..." << std::endl; std::vector<Foo> vec3; vec3.reserve(5); std::cout << "-------------" << std::endl; std::cout << "vec3 size:" << vec3.size() << std::endl << std::endl; return 0;}用gcc编译程序:g++ -std=c++0x -o test -O2 test.cpp,然后./test执行程序,结果如下: ...

June 23, 2019 · 1 min · jiezi

ArrayList-线程安全性学习

引言最近学校的氛围比较活跃,考研的复习,不考研的都在写简历准备面试。 看了看,最近也没有好公司来办宣讲会,也就没了投简历的意向。最近看了看面试题,想着补一补基础,以后面几家Spring Cloud的企业,去和面试官交流交流。 Spring Cloud的学习与体会 最近看了《Spring Cloud微服务实战》一书,感觉受益匪浅,大有裨益。 高并发应用,必须是要启用Spring Cloud的。有了Spring Cloud,就不用再像之前一样,前端工程师团队,后端工程师团队,运维团队。而是按模块划分,订单模块团队,支付模块团队,每个团队里都是从前端到后台到运维的全栈工程师。 就像上次黄庭祥说的,ThinkPHP开发,他写学期管理;AngularJS开发,他又写学期管理;Angular开发,他还写学期管理。想到什么了么?肯定精通这个模块的业务逻辑啊? 如果培养出优秀的支付模块团队、优秀的安全模块团队、优秀的高并发优化团队,其实淘宝也不过如此。 相互的依赖,从原来的@Autowired转为服务器接口间的调用。每个模块都是一个Spring Cloud应用,各应用间通过互相调用、相互协作共同实现业务功能,同时,各应用模块可以采用不同的数据库,以发挥各数据库之所长。 然后后台分布式部署,到了并发的时候,给相应的模块加服务器负载均衡就是了。个人中心模块,不常用,两个服务器负载;订单模块,可能会并发,加个百十来个服务器负载均衡。当然,像618、双十一这样的场景,肯定不是加服务器就能解决的,我这里只是举个简单的例子。模块划分之后,可以有针对性地解决高并发问题。 不扯淡了,开始进入正题。 面试题再谈线程安全什么是线程安全? 我看到这道题就感觉怎么也说不出来,就是多线程的环境下运行,我这个应用也不炸,虽然是这个意思,但是也不能这样回答啊?一时之间,找不到相关的学术词汇回答此问题。 这是想了许久后,我自己总结出的回答: 程序在单线程环境下正常执行得到了正确的结果,在多个线程并发执行的环境条件下,仍然能得到像单线程一样正确的结果,这就是线程安全。 如果一个类(或对象),我们在使用时,无需考虑任何多线程相关的问题,就像单线程一样使用,且最后能得到正确的结果,那就说这个类(或对象)是线程安全的。 ArrayList线程安全吗?看了许多面试题,发现面试官都喜欢以一个小方面进行切入,然后无限扩展,直到把面试者问懵圈为止。 ArrayList线程安全吗? 虽然天天用ArrayList,但是真的没考虑过这个问题。其实,ArrayList线程不安全。 ArrayList是一个内部采用数组实现的线性表,它相比数组最大的优点就是使用时可以不用去像数组一样new的时候去考虑要容纳多少个元素。ArrayList默认构造一个容量为10的数组。 private static final int DEFAULT_CAPACITY = 10;如果容量不够了,ArrayList会自动扩容,扩容至原来的1.5倍。(右移一位,相当于除以2)。 int newCapacity = oldCapacity + (oldCapacity >> 1);ArrayList没有对多线程问题进行处理,举个add方法的例子就能证明它线程不安全。 elementData[size++] = e;别看这是一行,其实是执行了两步操作,赋值和自增。 线程A add一个元素,然后暂停执行,size还没自增,然后线程B再add元素,size没变,就直接把A add的元素覆盖了。 不安全为什么要使用?又回到了之前向晨澍请教的问题,线程安全,必然是有额外开销的。 所以List的三个接口ArrayList、LinkedList和Vector。 线程不安全的要比线程安全的执行效率高。所以我们常用的是线程不安全的ArrayList、LinkedList,而从来没有用过线程安全的Vector。 Vector自JDK1.0就存在,设计得不够完善,多线程情况下如果使用不当也会发生错误,不推荐使用。 如何解决线程不安全既然Vector不能用,那我就想要一个线程安全的List得怎么整呢? 调用Collections.synchronizedList方法,使ArrayList线程安全。 List<String> synchronizedList = Collections.synchronizedList(new ArrayList<>());返回SynchronizedList类的对象,经典的装饰器模式,对方法访问加了同步。 public void add(int index, E element) { synchronized (mutex) {list.add(index, element);}}public E remove(int index) { synchronized (mutex) {return list.remove(index);}}总结何处望神州?满眼风光北固楼。千古兴亡多少事?悠悠。不尽长江滚滚流。年少万兜鍪,坐断东南战未休。天下英雄谁敌手?曹刘。生子当如孙仲谋。 ...

May 11, 2019 · 1 min · jiezi

leetcode中的vector常见用法

vector介绍我对vector的认识就是C++提供的包装好的数组,即对象的集合,一般来说,刷题过程中普通数组都可以用vector来代替,毕竟vector有很对简单用法并且不用考虑长度问题。因为是基础用法部分,就不深究vector和数组的区别以及vector的特性了,直接进入使用吧 本vector用法说明由于只是针对leetcode刷题所写的常用用法,所以内容可能比较简略,只是vector的部分内容。 声明虽然leetcode上自动包含了所有头文件,但是如果自己编程使用vector要加上头文件 #include <vector>再加上using namespace std;或者using std::vector;创建,复制vector<int> a; //创建一个空的vectorvector<int> a(n); //创建一个含有n个对象的vector, //此时数据已缺省构造产生,比如现在的数组里全是0vector<int> a(n, elem);//创建一个含有n个elem拷贝的vectorvector<int> a1(a2); //复制一个vectorvector<int> a1(begin, end); //这里的begin和end可以是另一个vector的迭代器 //会将[begin,end)范围内的数据复制过来关于最后一个用法有一个小坑可以注意一下,假设a2是一个含有4个int数据的vector,如果你是这样用的:vector<int> a1(a2.begin(), a2.begin()+3),那么a1中实际有3个对象;但如果你是这样用的:vector<int> a1(a2.begin(), a2.end()),那么a1中实际有4个对象。这是因为a2.end()实际上指向的并不是vector最后一个对象,而是最后一个对象的下一个位置。 一般来说,leetcode刷题过程中都不用手动释放vector内存,所以我也就不写了 访问数据a.begin() 返回指向首个对象的指针,也就是一般所说的迭代器a.end() 返回指向最后一个对象的下一个位置的指针a.begin()+1 返回指向首个对象的下一个对象的指针a.end()-1 返回返回指向最后一个对象的指针a.rbegin() 返回指向最后一个对象的指针,反向迭代器a.rend() 返回指向首个对象的前一个位置的指针,反向迭代器迭代器我个人觉得一开始不用深究,只需要知道他们是指向vector对象的指针即可反向迭代器很容易搞混。。可以不用,如果用的话要记住,rend和end分别在vector的两头 a.front() 返回首个对象的数据,和*a.begin()是一样的a.back() 返回最后一个对象的数据a.at(i) 返回编号i位置处的对象数据,会检查数据是否存在a[i] 返回编号i位置处的对象数据这里建议大家尽量使用a.at(i)来返回数据,因为会检查数据是否存在 插入a.push_back(i); //最简单的插入,直接向vector末尾加入一个数据a.insert(pos,elem); //向pos迭代器指向的对象前插入一个对象,注意是对象前a.insert(pos, n, elem); //向pos迭代器指向的对象前插入n个相同对象a.insert(pos, begin, end); //向pos迭代器指向的对象前插入[begin,end)之间的对象后三个函数都会返回新数据的位置 删除a.clear(); //删除所有对象a.pop_back(); //删除最后一个对象a.erase(pos); //删除pos迭代器对应的对象a.erase(begin, end); //删除[begin,end)之间的对象后两个函数会返回被删除数据的下一个位置 赋值a[1] = 1; //令编号1的对象数据为1a.assign(1, 1); //令a为{1}a.assign(begin,end); //把另一个迭代器[begin,end)中的数据赋值给a要注意第一行和第二行结果是完全不同的,assign函数有点类似复制函数,是对整体的操作 其它常用函数a.size() 返回vector中元素的个数a.empty() 返回vector是否为空,空返回1,不为空返回0a1.swap(a2); //交换a1,a2数据swap(a1, a2); //交换a1,a2数据,同上swap(a1[1], a1[2]); //交换a1的第2个数据和第3个数据 注意,是没有a1[1].swap(a1[2])这种用法的 ...

May 1, 2019 · 1 min · jiezi

Android4.4 及以下TextView,Button等控件使用矢量图报错

1 问题描述最近项目开发中,图标资源我尽量使用了矢量图,然而配置了基本的兼容设置,程序在低版本中运行还是出现了问题。xml布局文件中,在TextView中使用矢量图,比如android:drawableStart,android:drawableStart这些属性直接引用矢量图资源。这样在Android5.0及以上是没问题的,但是5.0以下就抛出找不到图片资源的问题。2 原因support库并没有为AppcompatTextView,AppcompatButton等控件适配设置矢量图属性,反正我就记得ImageView,ImageButton有srcCompat属性就是适配了的。3 解决方案基础配置(必须):1 在gradle里加上vectorDrawables 兼容支持android { … defaultConfig { … vectorDrawables.useSupportLibrary = true } …}2 在Application或者Activity上加上AppCompateDelegate开启CompatVectorFromResources支持 /** * vector兼容5.0以下系统 */ static { int currentapiVersion = android.os.Build.VERSION.SDK_INT; if (currentapiVersion < 21){ //适配android5.0以下 AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); } }方案1:矢量图包装为selector如果将就Android4.4,Button就不能用矢量图,要用位图,那还叫锤子的兼容支持,我也不知道Google官方为毛不在兼容控件上多加几个支持属性。参考stackOverFlow的回答,Button,TextView,应用矢量图,保险的是先把矢量图转为selector,然后selector代替矢量图使用,我觉得这是最佳的办法。例如: <Button style="@style/SettingItemTheme" android:layout_width=“match_parent” android:layout_height="@dimen/setting_item_height" android:text="@string/my_setting" android:id="@+id/my_btn_setting" android:drawableStart="@drawable/selector_setting" android:drawableEnd="@drawable/selector_right"/>selector_setting.xml<?xml version=“1.0” encoding=“utf-8”?><selector xmlns:android=“http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/ic_my_setting”/></selector>这里android:drawableStart,android:drawableEnd,我引用的是selector,但是selector里面就是一个默认的矢量图,但用这种方式布局,在Android4.4下运行程序就不会报错。方案2:不支持的就使用位图如果项目做了大半,突然说之前的矢量图不能用,要改为位图,这是很崩溃的。4 扩展:为什么我要用矢量图,而不是位图最常见的设置界面:我不知道各位实现设置Item的方式是怎样的,我实现UI的原则是能用一个控件实现就用一个实现,所以Item我用一个Button控件就实现了。Button,TextView自带drawableStart属性,可以在上下左右放图标,所以何必要用LinearLayout包三个控件实现呢。例如: <Button style="@style/SettingItemTheme" android:layout_width=“match_parent” android:layout_height="@dimen/setting_item_height" android:text="@string/my_vehicle_manage" android:id="@+id/my_btn_vehicle_manage" android:drawableStart="@drawable/selector_vehicle_manage" android:drawableEnd="@drawable/selector_right"/>但是如果drawableStart引用的是位图,这样图标的大小就很难调节,总是要找设计师重新切图,麻烦。但是用vector向量图就可以通过android:width,android:height调大小,这对开发来说很方便。

February 17, 2019 · 1 min · jiezi