您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“C++運(yùn)算符重載和返回值優(yōu)化的方法”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
  編譯環(huán)境還是針對(duì)C6455 DSP,為了做一些簡(jiǎn)單的圖像直方圖的處理,并且盡可能不用模板類(lèi),我自己寫(xiě)了一個(gè)簡(jiǎn)單的類(lèi)用來(lái)存放帶長(zhǎng)度信息的數(shù)組,并且可以做一些簡(jiǎn)單的運(yùn)算。重載了減法運(yùn)算符,從而可以對(duì)兩個(gè)直方圖求差。
  當(dāng)類(lèi)中有那種需要?jiǎng)討B(tài)分配空間的成員的時(shí)候,要記得提醒自己重載拷貝構(gòu)造函數(shù)和賦值運(yùn)算符,這兩者缺一不可。為了舉個(gè)例子,我定義了下面這個(gè)CData類(lèi)。
class CData { private: int *m_pData; unsigned int m_nLen; public: CData(); CData(unsigned int nLen); /* There is no copy constructor at the very begining */ CData(const CData &data); ~CData(); int &at(unsigned int i); int &at(unsigned int i) const; CData operator-(const CData &data); CData &operator=(const CData &data); CData &operator-=(const CData &data); };
  在CData中,有兩個(gè)成員,分別是一個(gè)int類(lèi)型的指針和一個(gè)unsigned int類(lèi)型的變量代表數(shù)據(jù)的個(gè)數(shù)。
  我重載了一個(gè)減法運(yùn)算符,為的是將兩個(gè)CData類(lèi)型的數(shù)據(jù)長(zhǎng)度相同的對(duì)象中的每個(gè)對(duì)應(yīng)位置的int類(lèi)型數(shù)據(jù)直接相減。而在調(diào)用減法運(yùn)算的時(shí)候勢(shì)必會(huì)用到拷貝構(gòu)造函數(shù)和賦值運(yùn)算符,因此也需要對(duì)它們重載。
  順帶一提的是,在上面我還聲明了一個(gè)“-=”運(yùn)算符的重載,為的是突出“-=”在一定場(chǎng)合會(huì)更加高效,但因?yàn)槲以趯?shí)際應(yīng)用中不能直接覆蓋“被減數(shù)”中的數(shù)據(jù),所以不能用“-=”運(yùn)算符,只能通過(guò)減法運(yùn)算符來(lái)實(shí)現(xiàn)。
CData CData::operator-(const CData &data) { cout << "entering subtract" << endl; assert(m_nLen == data.m_nLen); CData ret(data.m_nLen); for (int i = 0; i < m_nLen; i++){ ret.at(i) = at(i) - data.at(i); } return ret; }
  減法運(yùn)算重載,返回值是一個(gè)類(lèi)的對(duì)象。函數(shù)返回后,這個(gè)類(lèi)的對(duì)象就已經(jīng)被析構(gòu)了,所以在它被析構(gòu)之前一般會(huì)先調(diào)用一個(gè)拷貝構(gòu)造函數(shù),將這個(gè)類(lèi)的對(duì)象拷貝給一個(gè)新的臨時(shí)的對(duì)象。默認(rèn)拷貝構(gòu)造函數(shù)采用淺拷貝,這在遇到類(lèi)中包含指針類(lèi)型的成員時(shí)很可能造成對(duì)同一塊內(nèi)存區(qū)域的重復(fù)釋放。所以我們需要重載拷貝構(gòu)造函數(shù),為指針成員申請(qǐng)新的內(nèi)存空間。
CData CData::&operator=(const CData &data) { cout << "entering assign" << endl; assert(m_nLen == data.m_nLen); for (int i = 0; i < m_nLen; i++) at(i) = data.at(i); return *this; }
  減法運(yùn)算返回的臨時(shí)對(duì)象如果不給新的對(duì)象接收,它就沒(méi)了。所以我們還需要重載賦值運(yùn)算符,用來(lái)接收這個(gè)臨時(shí)對(duì)象中的數(shù)據(jù),這一臨時(shí)對(duì)象被接收后,也會(huì)被析構(gòu)。分析整個(gè)過(guò)程可以看到,從減法運(yùn)算返回的類(lèi)對(duì)象,其中的數(shù)據(jù)先要被復(fù)制到一個(gè)臨時(shí)對(duì)象里,再要從臨時(shí)對(duì)象復(fù)制到真正的賦值目標(biāo)對(duì)象里,浪費(fèi)了很多時(shí)間。
  有的編譯器就會(huì)對(duì)這樣的情況進(jìn)行優(yōu)化,省略對(duì)拷貝構(gòu)造函數(shù)的調(diào)用,直接賦值。
  我今天遇到的問(wèn)題是因?yàn)?,我之前不知道在這個(gè)過(guò)程中會(huì)調(diào)用拷貝構(gòu)造函數(shù),所以沒(méi)有重寫(xiě)拷貝構(gòu)造函數(shù)。意外的是,之前我這么做也是能用的,但我現(xiàn)在覺(jué)得不管怎樣還是得把拷貝構(gòu)造函數(shù)寫(xiě)上,不能偷懶。
  為了便于驗(yàn)證這一過(guò)程,我寫(xiě)了一部分測(cè)試代碼,可以用g++編譯。
#include <assert.h> #include <iostream> using namespace std; class CData { private: int *m_pData; unsigned int m_nLen; public: CData(): m_nLen(0), m_pData(nullptr) { cout << "construct without arg" << endl; } CData(unsigned int nLen): m_nLen(nLen) { cout << "construct with arg" << endl; m_pData = new int[nLen]; assert(m_pData != NULL); } CData(const CData &data) { cout << "copy construct" << endl; m_nLen = data.m_nLen; m_pData = new int[data.m_nLen]; assert(m_pData != nullptr); for (int i = 0; i < m_nLen; i++){ at(i) = data.at(i); } } ~CData() { cout << "destruct" << endl; if(m_pData){ delete[] m_pData; m_pData = nullptr; } } int &at(unsigned int i) { assert(i < m_nLen); return *(m_pData + i); } int &at(unsigned int i) const { assert(i < m_nLen); return *(m_pData + i); } CData operator-(const CData &data) { cout << "entering subtract" << endl; assert(m_nLen == data.m_nLen); CData ret(data.m_nLen); for (int i = 0; i < m_nLen; i++){ ret.at(i) = at(i) - data.at(i); } return ret; } CData &operator=(const CData &data) { cout << "entering assign" << endl; assert(m_nLen == data.m_nLen); for (int i = 0; i < m_nLen; i++) at(i) = data.at(i); return *this; } CData &operator-=(const CData &data) { cout << "entering subtract and assign" << endl; assert(m_nLen == data.m_nLen); for (int i = 0; i < m_nLen; i++) at(i) -= data.at(i); return *this; } }; int main() { cout << "---------- start construct ----------" << endl; CData dataA(10); CData dataB(10); CData dataC(10); cout << "---------- start subtract ----------" << endl; dataC = dataA - dataB; cout << "---------- start subtract and assign ----------" << endl; dataA -= dataB; cout << "---------- end of program ----------" << endl; return 0; }
  g++編譯的程序,返回類(lèi)對(duì)象的時(shí)候,默認(rèn)是會(huì)省略拷貝構(gòu)造函數(shù)的,加上“-fno-elide-constructors”的編譯選項(xiàng)后可以讓它不省略。
  上圖是在加上了“-fno-elide-constructors”編譯選項(xiàng)后的運(yùn)行結(jié)果,可以看到執(zhí)行了兩次析構(gòu),對(duì)應(yīng)減法重載函數(shù)內(nèi)的對(duì)象和拷貝構(gòu)造函數(shù)生成的臨時(shí)對(duì)象被析構(gòu)。
  而沒(méi)有“-fno-elide-constructors”選項(xiàng)的時(shí)候,就只會(huì)有一次析構(gòu),因?yàn)闆](méi)有調(diào)用拷貝構(gòu)造函數(shù)。
如果加了這個(gè)選項(xiàng),但是沒(méi)有重寫(xiě)拷貝構(gòu)造函數(shù),就會(huì)在第二次析構(gòu)的時(shí)候產(chǎn)生重復(fù)釋放內(nèi)存的問(wèn)題。
“C++運(yùn)算符重載和返回值優(yōu)化的方法”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。