Thinking again in C++(二)自賦值是非公斷 (轉)
愛死Thinking in系列了,所以起了這個名字。本文的思想也部分來至於這套書,或參照對比,或深入挖掘,或補益拾慧,或有感而發,既包括Thinking in C++,甚至也包括Thinking in 。
Thinking again in C++(二)自賦值是非公斷
關鍵字:C++,自賦值,自複製,賦值,assign,assignment,複製,複製,copy
1.需要考慮的自賦值。當類包含指標或引用成員時應注意檢查。
class String
{
private:
char * pc_Buffer;
public:
String & operator=(const String & strR);
String & operator+=(const String & strR);
//...
};
(1)類內部:對稱賦值運算子、接受自身型別或自身基類型別引數的成員,有時候還要考慮+=系列運算子。
String & String::operator=(const String & strR)
{
if (this==&strR) 1]
return *this;
delete [] pc_Buffer; 2]
pc_Buffer=new char[strlen(strR.pc_Buffer)+1];//[3]
//...
}
[1]中的判斷是必須的。如果this==&strR,[2]將本身刪除,[3]就會使用“懸掛指標”。
下面operator+=()的實現隱藏著錯誤。
String & String::operator+=(const String & strR)
{
int iLengthNew=strlen(pc_Buffer)+strlen(strR.pc_Buffer);
char * pcBufferNew=new char[iLengthNew+1];
strcpy(pcBufferNew,pc_Buffer);
delete [] pc_Buffer; 4]
strcat(pcBufferNew,strR.pc_Buffer); 5]
pc_Buffer=pcBufferNew;
return *this;
}
如果this==&strR,[4]將本身刪除,[5]就會使用“懸掛指標”。正確的做法不必使用判斷語句,只需調換[4][5]兩條語句的順序。
(2)類外部(包括友元):接受多個同一型別引數或多個有繼承關係的型別引數的函式。
class CDerive : public CBase{};
void f(CBase & b1,CBase & b2);
void g(CBase & b,CDerive & d);
CBase bSame;
CDerive dSame;
f(bSame,bSame); 1]
f(dSame,dSame); 2]
g(dSame,dSame); 3]
[1][2][3]都出現了自賦值,所以f()、g()的設計中都要有所考慮。
2.不可能出現自賦值。
(1)複製構造器:因為正在構造的還未完全生成,而傳遞給構造器的實參物件是已構造完畢的物件,這兩者絕不可能是同一物件。
(2)非對稱賦值運算子:即使形參型別是自身的基類。若D是B的派生類,無論是否過載了對稱賦值運算子,D類物件之間的賦值行為都不會D::operator=(const B & b)。
class CDerive : public CBase
{
public:
operator=(const CBase & b); 用考慮this和b之間的自賦值
void f(const CBase & b); 要考慮this和b之間的自賦值
};
CDerive dSame;
dSame=dSame; 1]
dSame.f(dSame); 2]
語句[1]中,不會把dSame上溯造型為CBase,而是呼叫預設或自定義的D::operator=(const D & d)。只有等式左邊確為D,右邊確為B,才呼叫D::operator=(const B & b),這時不可能出現自賦值。相反,語句[2]中,編譯器會把dSame上溯造型為CBase,所以f()需要考慮自賦值。
3.不是自賦值的賦值。僅僅內容相同的賦值不是自賦值。
CTest a,b,same;
a=same;
b=same;
a=b; 1]
[1]不是自賦值,不會出問題,不需要檢查,而且內容相同無法直接用地址來檢查。
4.不應該檢查的自賦值。
strcpy(char * strDest,const char * strSrc);中,當strDest==strSrc時,是自賦值,但並不會出錯。
發現自賦值直接返回,這種特定情況下,也許能提高函式10倍,但絕大多數沒有出現自賦值時都多了一個條件判斷,可能降低函式效率10%,最後綜合計算加權平均效率可能還是降低了。這取決於自賦值出現的機率。
設不判斷自賦值,函式時間為1;若檢查自賦值,設出現自賦值的機率為x,直接返回函式執行時間為0.1,不出現自賦值,多了一個條件判斷函式執行時間為1.1,那麼如果要求加權平均效率不降低:
0.1x+1.1(1-x)<1
解之,得:x>0.1。也就是說自賦值出現的機率必須大於10%,這在實際程式碼中可能嗎?
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-982478/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 【c++】深賦值與淺賦值C++賦值
- php 自增賦值PHP賦值
- 肯定賦值斷言與非空斷言賦值
- 物件賦值轉換物件賦值
- 賦值運算子(轉)賦值
- C++ 初始化與賦值C++賦值
- 【c++】異常安全深賦值C++賦值
- java裡面給物件賦值,慎用賦值符號(=) (轉)Java物件賦值符號
- C++物件模型之五 構造 析構 賦值筆記 (轉)C++物件模型賦值筆記
- jquery取值和賦值(包含部分是原生js的取值和賦值)jQuery賦值JS
- 《Effective C++》閱讀總結(二):類的構造、析構和賦值C++賦值
- 第二天:識別符號、賦值、資料型別、格式符、常量、自動轉換、強制轉換。符號賦值資料型別
- 頁面資料賦值轉換賦值
- 給物件引用變數賦值(轉)物件變數賦值
- 求救!Actionform是怎麼樣賦值的?ORM賦值
- 如何解決自增列賦值的問題賦值
- Java判斷欄位是否為空,為空賦值 ?Java賦值
- php之普通變數賦值、物件賦值、引用賦值的區別PHP變數賦值物件
- js如何判斷一個變數是否宣告並賦值JS變數賦值
- Prefer C++ (二) (轉)C++
- C++筆記 11:在operator中處理“自我賦值“C++筆記賦值
- C++特點,物件的概念,初始化和賦值C++物件賦值
- PbootCMS整理判斷是否連結賦值各種條件判斷和標籤boot賦值
- 變數的賦值 指標間接賦值變數賦值指標
- 常被新手忽略的值賦值和引用賦值(偏redux向)賦值Redux
- Verilog連續賦值、過程賦值、過程連續賦值總結賦值
- Class.isAssignableFrom判斷A類是否可賦值給B類賦值
- (entity bean)動態賦值值物件-- Dynamic Create Value Object 模式 (轉)Bean賦值物件Object模式
- Effective c++條款11:在operator=中處理“自我賦值”C++賦值
- C++複製控制:賦值操作符和解構函式C++賦值函式
- javascript變數賦值或者重新賦值注意事項JavaScript變數賦值
- **PHP二維陣列遍歷時同時賦值PHP陣列賦值
- 陣列賦值陣列賦值
- 解構賦值賦值
- PLSQL Language Reference-PL/SQL語言基礎-變數賦值-使用賦值語句賦值SQL變數賦值
- 動態賦值弱型別值物件--Dynamic Create Value Object 模式 (轉)賦值型別物件Object模式
- 警惕自己,不斷學習c++【轉】C++
- C++左值右值完美轉發轉移C++