C++性能优化之一:合理使用内存

要想在编码过程中,写出高效的代码,是需要自己长期的总结和不断学习的。工作以来,我自己也总结了一些小技巧,可以让你的程序运行的更快、内存空间使用更合理,同时我还会不断地补充该blog,争取建立出一个属于自己的c++ effective系列。

不多说,直接进入正题,以下都是我再编程过程中,总结出来c++高效编码规则,每个topic对应一个规则。

局部变量合理使用

让我们先看一段代码:

for (int i = 0; i < 1000; ++i)
{
    string str = "do some thing:" + int2str(i);
    func(str);
}

这段代码,在循环中使用局部变量拼装函数func的入参,在每次循环过程中,str对象都会执行一次构造函数和析构函数,那么,在这个for循环中,单单是str的组装就耗费了1000次的内存申请和释放,局部变量占用内存小的话,影响不会很大,如果动辄几十、几百kb,那就会造成系统内存使用的波动,那么是不是有更高效的方法?

其实只需要把str变量放到for循环外部声明即可,如下面代码:

string str;
for (int i = 0; i < 1000; ++i)
{
    str = "do some thing:" + int2str(i);
    func(str);
}

这段代码会大大降低内存的申请和释放次数,因为首次循环后,str会申请15个字节的内存空间来容纳现有数据,第二次循环时,在赋值运算符函数中,由于str当前空间已经足够容纳第二次循环的数据,因此我们可以考虑对原有str内存进行复用,所以只存在一次数据拷贝,不存在新的内存申请和释放;到第十次循环时,需要16个字节才能容纳现有数据,因此需要释放str原有内存,申请新的内存。以此类推,我们可以算出1000次循环过程中,只有三次内存申请和释放,大大降低了内存的申请和释放次数。

小结:在循环体中,局部变量如果占用内存空间较大,会造成内存使用不合理,可以考虑放到循环体外声明。

左值引用的合理使用

左值引用提升程序性能的应用场景。
首先是函数入参,看下面两个函数的声明,func1会存在一次str副本的拷贝构造的过程,且退出函数体,还需要释放str,而func2直接将str的地址传入函数体内部,不存在拷贝构造,如果str内存很大,那么节约一次拷贝的收益还是很可观的。

void func1(const string str);  //存在冗余拷贝构造和析构
void func2(const string& str); //直接传递str变量的地址

其次是循环体中,获取数组元素时,如果我们不需要修改原始值,那么应该是使用常引用直接指向数组元素的地址,避免局部变量的冗余的拷贝构造和析构

for (int i = 0; i < arrstrs.size(); ++i)
{
    string str = arrstrs[i];        //存在冗余拷贝构造和析构
    const string& str = arrstrs[i]; //直接使用arrstrs[i]变量的地址
    ...
}

动态数组容量提前设定

分层架构的代码中,经常出现需要对不同层次数据规格进行转换,即把其他层次的数据转化为所在层的数据格式,以下是项目中经常看见的一段代码,主要目的是把第二层的数据转化到第一层坐标数据中,代码如下:

//变量格式声明
typedef struct _FirstLayer_PosData_t
{
    double x;
    double y;
}FirstLayer_PosData_t;
typedef struct _SecondLayer_PosData_t
{
    double x;
    double y;
    int    tag;
}SecondLayer_PosData_t;
vector<FirstLayer_PosData_t> arrfir;
vector<SecondLayer_PosData_t> arrsec;
//层数据转化代码
for (int i = 0; i < arrsec.size(); ++i)
{
    FirstLayer_PosData_t stFirstLayerPos;
    stFirstLayerPos.x = arrsec[i].x;
    stFirstLayerPos.y = arrsec[i].y;
    arrfir.push_back(stFirstLayerPos);
}

这段代码可以这样改进,其实我们要拷贝的元素个数是已知的,因此我们可以直接将arrfirst数组大小设置为arrsecond的大小即可,这就避免了在循环体中动态的去扩容(每次扩容的成本是先申请新的内存空间,将旧内存空间数据拷贝到新内存空间,然后释放旧内存空间),改进代码如下:

arrfir.setsize(arrsec.size());
for (int i = 0; i < arrfir.size(); ++i)
{
    FirstLayer_PosData_t stFirstLayerPos;
    stFirstLayerPos.x = arrsec[i].x;
    stFirstLayerPos.y = arrsec[i].y;
    arrfir[i] = stFirstLayerPos;
}

仔细观察下,其实还有优化空间,局部变量是可以避免的,直接使用引用代替第一层数组的每个元素即可,最终优化代码如下:

arrfir.setsize(arrsecond.size());
for (int i = 0; i < arrfirst.size(); ++i)
{
    FirstLayer_PosData_t& stFirstLayerPos = arrfir[i];
    stFirstLayerPos.x = arrsec[i].x;
    stFirstLayerPos.y = arrsec[i].y;
}

move语义的合理使用

TODO

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,084评论 1 32
  • 1.设计模式是什么? 你知道哪些设计模式,并简要叙述?设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类型...
    龍飝阅读 2,133评论 0 12
  • 最全的iOS面试题及答案 iOS面试小贴士 ———————————————回答好下面的足够了-----------...
    zweic阅读 2,689评论 0 73
  • 每个人都是因为偶然和幸运而生,或是星星,或是花草,或是泥石,或是风雨,各自都有自己所属的星空。如果你是一朵花,闪亮...
    总督岛秦观阅读 170评论 2 1
  • 六年前的今天,差不多也是这个时间,我们奔赴在人生第一次与彼此见面的路上; 两年前的今天,我们领证了; 一年前的今天...
    茶颜阅读 244评论 0 0