要想在編碼過程中,寫出高效的代碼,是需要自己長期的總結和不斷學習的。工作以來,我自己也總結了一些小技巧,可以讓你的程序運行的更快、內存空間使用更合理,同時我還會不斷地補充該blog,爭取建立出一個屬于自己的c++ effective系列。
不多說,直接進入正題,以下都是我再編程過程中,總結出來c++高效編碼規(guī)則,每個topic對應一個規(guī)則。
局部變量合理使用
讓我們先看一段代碼:
for (int i = 0; i < 1000; ++i)
{
string str = "do some thing:" + int2str(i);
func(str);
}
這段代碼,在循環(huán)中使用局部變量拼裝函數(shù)func的入參,在每次循環(huán)過程中,str對象都會執(zhí)行一次構造函數(shù)和析構函數(shù),那么,在這個for循環(huán)中,單單是str的組裝就耗費了1000次的內存申請和釋放,局部變量占用內存小的話,影響不會很大,如果動輒幾十、幾百kb,那就會造成系統(tǒng)內存使用的波動,那么是不是有更高效的方法?
其實只需要把str變量放到for循環(huán)外部聲明即可,如下面代碼:
string str;
for (int i = 0; i < 1000; ++i)
{
str = "do some thing:" + int2str(i);
func(str);
}
這段代碼會大大降低內存的申請和釋放次數(shù),因為首次循環(huán)后,str會申請15個字節(jié)的內存空間來容納現(xiàn)有數(shù)據,第二次循環(huán)時,在賦值運算符函數(shù)中,由于str當前空間已經足夠容納第二次循環(huán)的數(shù)據,因此我們可以考慮對原有str內存進行復用,所以只存在一次數(shù)據拷貝,不存在新的內存申請和釋放;到第十次循環(huán)時,需要16個字節(jié)才能容納現(xiàn)有數(shù)據,因此需要釋放str原有內存,申請新的內存。以此類推,我們可以算出1000次循環(huán)過程中,只有三次內存申請和釋放,大大降低了內存的申請和釋放次數(shù)。
小結:在循環(huán)體中,局部變量如果占用內存空間較大,會造成內存使用不合理,可以考慮放到循環(huán)體外聲明。
左值引用的合理使用
左值引用提升程序性能的應用場景。
首先是函數(shù)入參,看下面兩個函數(shù)的聲明,func1會存在一次str副本的拷貝構造的過程,且退出函數(shù)體,還需要釋放str,而func2直接將str的地址傳入函數(shù)體內部,不存在拷貝構造,如果str內存很大,那么節(jié)約一次拷貝的收益還是很可觀的。
void func1(const string str); //存在冗余拷貝構造和析構
void func2(const string& str); //直接傳遞str變量的地址
其次是循環(huán)體中,獲取數(shù)組元素時,如果我們不需要修改原始值,那么應該是使用常引用直接指向數(shù)組元素的地址,避免局部變量的冗余的拷貝構造和析構
for (int i = 0; i < arrstrs.size(); ++i)
{
string str = arrstrs[i]; //存在冗余拷貝構造和析構
const string& str = arrstrs[i]; //直接使用arrstrs[i]變量的地址
...
}
動態(tài)數(shù)組容量提前設定
分層架構的代碼中,經常出現(xiàn)需要對不同層次數(shù)據規(guī)格進行轉換,即把其他層次的數(shù)據轉化為所在層的數(shù)據格式,以下是項目中經??匆姷囊欢未a,主要目的是把第二層的數(shù)據轉化到第一層坐標數(shù)據中,代碼如下:
//變量格式聲明
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;
//層數(shù)據轉化代碼
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);
}
這段代碼可以這樣改進,其實我們要拷貝的元素個數(shù)是已知的,因此我們可以直接將arrfirst數(shù)組大小設置為arrsecond的大小即可,這就避免了在循環(huán)體中動態(tài)的去擴容(每次擴容的成本是先申請新的內存空間,將舊內存空間數(shù)據拷貝到新內存空間,然后釋放舊內存空間),改進代碼如下:
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;
}
仔細觀察下,其實還有優(yōu)化空間,局部變量是可以避免的,直接使用引用代替第一層數(shù)組的每個元素即可,最終優(yōu)化代碼如下:
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