1 无疑使用const引用是一个好习惯,除非有理由拒绝它

在C++中容器都是值拷贝的,因此不使用引用的化,会大量拷贝垃圾数据
其实,可以这么说C/C++是值拷贝编程语言。不使用额外的技术,比如指针、引用,都会发生垃圾数据的拷贝。当然,到底是不是垃圾数据由你自己决定,值拷贝是无法彻底摒弃的。

2 看一个案例

下面是一个提交记录,注意红色方框的部分,加上引用,和不加引用的区别
两次消耗内存的,相比下,节省了90M,你想想90M内存要存多少int的数据???
时间也节省了很多,16ms的CPU处理时间,,,
在这里插入图片描述

3 不改变元素一定要加上const,不需要拷贝需要加上&

其实,有时候要返回一个空的容器,那么问题来了,返回值不能是空容器的引用,语法错误,
这时候,你直接放进形参[out]即可
最重要的是,不要把容器作为返回值,至少有如下缺点

  1. 不能返回空容器的引用
  2. 返回临时变量的引用,直接异常

其实函数的返回值的目的是记录函数是否正确运行,没有出错,void就行了

4 最后,简谈下数组和容器

我觉的容器的一个最大的优点是,存储在堆上,也就是它的大小动态变化的,就是常使用的push_back方法。
这样很好,因为数组实际储存在栈上的,这样会导致不能定义大数组,比如在windows上栈的大小是1M,大概不超过26万个int, 2 10 ∗ 2 10 / 4 = 2 18 2^{10} * 2^{10}/4 =2^{18} 210210/4=218,Linux的栈是8M

我认为一个缺点是,使用下标访问的时候,容器的大小必须给定,比如在很多的API中,都需要提前给定容器的大小,当然后面提出了back_insert迭代器解决了这个问题,但是,其他其他任然会有问题

请看一个案例,这里用res做为输出,前面已经解释了不用容器最为返回值哈,由于传进来的res,容器为0,如果直接返回将会异常。

void count0_1(const string& str, vector<int>& res) {
    for (const auto& e : str){
    	res[0]++;		/**<ERROR */
    }
}

修改, 需要多少,我就提前push_back

void count0_1(const string& str, vector<int>& res) {
	/**<increase size of res*/
	for i to needed:
		res.push_back(0);
		
    for (const auto& e : str){
    	res[0]++;		/**<ERROR */
    }
}

当然,如果函数内部返回的数组大小已知,就用原始数组(栈),或者array,没错,array存储在堆上的。
下面看看,用array来解决固定大小数组的问题,
注意,array不会初始化,这里用初值列进行初始化,
实际上array和原始数组的性能基本一致,所以也建议使用。

void count0_1(const string& str, array<int, 2>& res) {
    for (const auto& e : str)
        ++res[e - '0'];
}

array<int, 2> weight{};		/**<2个固定大小的数组 */

用原始数组,

void count0_1(const string& str, int *res) {
    for (const auto& e : str)
        ++res[e - '0'];
}

int weight[2];

最后,总结下,不管怎么说,

  1. 函数返回值只是表征函数正确执行与否
  2. 形参是出参的很常见,尤其在C中,通过指针送出大量数据
  3. array的性能和原始数组差不多,C++人员不妨习惯使用它
  4. vector需要注意的是,容器大小没有提前给定,访问元素是错误的

一个小问题,既然堆上能分配大量数组,那么它的极限是多少呢?
很明显,和物理内存的大小有关,不过还与操作系统有关,比如下面一个常见的错误,
0x7fffffff 字节,也就是 2 31 2^{31} 231个元素,int的数据就有8G大小,感兴趣可以学习下

ERROR: 数组的总大小不得超过 0x7fffffff 字节
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐