c++应用程序优化之一变量内存的优化
c++可优化的细节非常多,从这次起开始一个个的说明一下,有些是来自书本,有些来自经验 ,有些来自网上的其它的一些资料,优化的方法是相同的,所以只介绍原理和方法。针对c++11及后续的c++新的版本库的一些特点,会对一些优化的细节进行综合说明。
一、字符串
字符串变量的优化是最常见的,也是最容易被忽略的。这里举一个简单的例子:
void Test(const std::string &s)
{
std::string str;
for (int num =0;num < s.length();num++)
{
str =str + s[i];//第一种
//改写成:
str += s[i];//第二种
}
}
如果用第一种的话,会产生临时字符串变量,也就是说分配内存N次,导致开销增加,在数据量巨大时,不可小觑。此外,这种连接表达式也会产生不必要的临时变量的产生,导致内存分配的增加。但是,在c++11的环境下,优秀的编译器会对此进行优化,利用移动构造函数来实现高效的指针复制。
如果涉及到大量的字符的处理,建议采用c的形式来处理而不是采用c++的字符串处理,这样虽然有点小麻烦,但是效率是最高的。
二、线性类容器的优化
其实其它的相关的线性容器都有类似的问题(比如上面的std::string也可以这样指定长度),看下面的代码:
std::vector<int> vec;
//vec.reserve(10000);//提前处理一下内存
for (int num =0;num < 10000;num++)
{
vec.push_back(num);
}
在循环比较小的情况下,vector的内存再次分配造成的开销是可以容忍的,如果大到一定程序,连续的内存分配和数据拷贝会极大的降低性能。可以用reserve来提前处理一下内存长度(注释部分),让其和相关的实际数据匹配。
三、大内存对象的指针或者引用传递
这个非常容易理解,如果向一个函数传递一个拥有较大的内存变量时,或者需要返回一个此类的对象时,临时对象的复制开销也是相当巨大的。因此,可以考虑使用引用或者指针来搞定,看下面的例子:
typedef struct __List__
{
int d;
char buf[100];
}MyList,*PMyList;
MyList GetValue(MyList oldlist)
{
MyList list;
......
return list;
}
int GetValue(MyList &old,Mylist &new)
{
new.d = old.d + 1;
....
return 0;
}
这样会大幅的减少临时变量的开销,提高效率。
四、移动语义
在c++11实现了移动语义后,拷贝构造函数的引用可以不再使用了,类似如下:
class String
{
public:
...
//C++98:
//String(const String& s);
//String& operator=(const String& s);
//C++11:
String(String s);
String& operator=(String s);
...
};
这个陈硕在网上有相关的评论,主要主是移动语义起得作用。这个目前还有一些争论,这里提出这个的目的是,一定要利用好c++11的移动语义来减少开销。
另外,在创建智能指针时尽量使用std::make_shared, 同样也是基于这个道理。
五、总结
这里总结得很唐突,只是想把这个开一个头,好不断的向前推进整个优化的总结。一点点先记下来,回头再整体统一进行整理。