本文件提出了複製建構函式,它是後複製函式的替代方法.複製建構函式消除了對後複製的需求,並修復了其缺陷和固有限制.還討論了演進和向後相容性.
本節重點介紹了後複製
存在問題,並說明了為什麼複製建構函式
比後複製
好.
無法有意義地過載或限定
後複製函式.但,編譯器不會拒絕限定器應用,如下所示:
構 a
}構 b
}構 c
}
存在限定詞的情況下,未定義後複製的語義,實驗表明該行為是打補丁式的:
常 不能修改目標中的任何欄位的後複製
不變 永遠不呼叫後複製(導致編譯錯誤)
共享 後複製位不能保證原子性
定義和實現有意義語義
將破壞在當前語義下經過測試並認為正確的**.
如上所述,不嚴格限制,後複製很難檢查型別,且同步成本過高.
該dip提出具有以下優點的複製構造
函式:
該特徵在c++語言上效果很好[3];
可按普通建構函式檢查複製建構函式
型別(由於不位複製,字段初始化方式與普通建構函式
相同);即按普通建構函式
檢查常/不變/共享
型別.
提供封裝.
缺點是使用者必須手動複製所有字段,且每次加字段到構時,必須修改複製構造
函式.但,使用d的自省機制
可輕鬆搞定.如,此簡單**可用作語言習語或庫函式:
foreach
(i,ref field;src.tupleof)
本.tupleof[i]
=字段;
如上所示,可用幾行**輕鬆替換後複製的好處.如下詳述,複製建構函式以最小語言複雜性解決後複製的問題.
本節討論有關複製建構函式語義的所有技術方面.
在構
定義內部,如果函式宣告中第乙個引數與構型別的非預設引用相同,其他所有引數都具預設值時
,則為複製建構函式.這種方式宣告複製建構函式
,優點是不用改解析器,語法可不變.例:
匯入 std.stdio ;
構 a//複製建構函式
本(引用 中 域 a rhs,
int b =
7)不變
//使用預設引數的複製建構函式
}空 main()
可顯式
呼叫複製建構函式(如上面的c),因為它也是先前語言語義中存在的建構函式.
按引用
傳遞複製建構函式的引數,避免無限遞迴(按值傳遞需要複製構,導致無限遞迴呼叫複製構造).注意,如果源是右值,則不需要呼叫複製建構函式,因為將按位移動(如必要)到目標中(即,優先移動構造).例:
構 a
}a 建立(
)空 main()
僅呼叫乙個複製構造
,在rhs位置的原
.然後,把右值放入值
.
可對複製構造函式引數/函式本身
應用型別限定器
,以允許定義跨不同可變級
物件拷貝.型別限定器是可選的.
本節討論複製建構函式和其他語言特徵間的語義分析和互動
關係.
為確保後複製
到複製建構函式的平穩過渡,此dip提出以下策略:如果乙個構定義了(使用者定義或生成
的)後複製,則忽略複製建構函式,優先後複製.現有的不使用後複製
**庫可開始使用複製建構函式
,而當前依賴後複製的**庫可使用複製建構函式
開始編寫新**並刪除後複製
.本dip建議棄用後複製,但未規定棄用時間表.
從後複製到複製建構函式語義上相近的轉換如下:
//新**
構 a
}//替換現有**
構 a ...
}
每當將構變數複製另乙個相同型別變數時,編譯器隱式插入複製構造函式呼叫:
顯式初化變數時:
構 a
}空 main()
按值
傳遞引數給函式時:
構 a
}空 函式(a a)
空 main()
從函式按值返回引數且無nrvo時:
構 a
}a 函式(
)a a;
a 槍(
)空 main()
按引用
傳遞複製構造函式引數,僅當源是左值時,降低初始化至複製構造函式呼叫.儘管可**臨時左值宣告至複製建構函式,但本dip不討論繫結右值到左值.
注意,函式返回定義了複製建構函式的構例項且無法nrvo時,在返回前,在呼叫點呼叫複製建構函式.如可nrvo,則刪除複製:
構 a
}a a;
a 函式(
)空 main()
複製建構函式與建構函式的型別檢查[6][7]一樣.
可顯式禁用
複製建構函式過載
:
構 a
}空 main()
為了禁用複製構建,必須禁用所有複製建構函式過載.在上面示例中,僅禁用了從可變到可變的複製;仍可呼叫從不變到可變複製過載.
可用(從合格的源複製的
)引數的不同限定器或複製建構函式自身(複製到合格目標)來過載
複製建構函式:
構 a
//-可變源,可變目標
本(ref 中 域 不變 a b)
// 2-可變源,可變目標
本(ref 中 域 a b)不變
// 3-可變源,不變目的地
本(引用 中 域 不變 a b)不變
//4不變源不變目標
}空 main()
使使用者能任意組合限定:常,不變,共享,常 共享
.
進出
用於限定變,常或不變
相同的型別:
構 a
}空 main()
部分匹配時,適用現有過載和隱式轉換規則
.
如果構未定義複製建構函式,則右邊儲存位置位刷
到左邊來初化.例:
構 a
空 main()
構定義複製建構函式時,將對該構禁用所有隱式位刷.例:
構 a
}空 函式(不變 a)
空 main()
構定義別名 本
及複製建構函式
可能衝突.如返回別名 本
型別是定義型別的特定
版本時,有歧義.例:
構 a
別名 函式 本;
本(引用 中 域 a)不變
}構 b
別名 函式 本;
本(ref 中 域 b b)
}//將這三個屬性合併為乙個.
空 main()
雖然複製建構函式和別名 本
都適合解決賦值問題時,複製建構函式比別名 本
優先順序更高,因為它更特定(複製建構函式目的就是建立副本
).如果未匹配過載集中的複製建構函式,則發出錯誤,即使使用從別名 本
理論上講也可生成匹配構造器.即,在複製構造
上,忽略別名 本
.
如滿足以下所有
條件,編譯器對構 s
,隱式
生成複製建構函式:
s 未顯式宣告任何複製建構函式;
s 至少有乙個定義具有複製建構函式
的直接成員,且該成員不與任何其他成員通過聯
重疊.
如滿足上述限制,則生成以下複製建構函式:
本(引用 中 域 進出(s)src)進出
定義複製建構函式的構不是pod.
如果聯 s
具有定義複製建構函式的字段,則每當s按複製初化型別物件
時,發出錯誤.重疊字段
(匿名聯合)也這樣.
按源物件可變引用傳遞複製建構函式的引數
.即複製構造函式呼叫可合法修改源物件:
構 a
}空 main()
允許非常
的引數,不然,太麻煩,還要常
為引數,裡面再把常
去掉.折騰.c++不推薦.
構 c
}空 函式(c c)
空 main()
具有上述定義建構函式只用作複製建構函式
. 複製建構函式
今天回看了前面的內容,發現這一章掌握的不夠好,就重看了一遍,順便總結一下 無規律總結 複製建構函式用於複製物件,即可以初始化物件,也可以將複製得到的物件作為實參傳遞給函式,多用於初始化。當我們這樣寫 string null bulk 9 9 9 9 在建立null bulk時編譯器先呼叫string...
複製建構函式
拷貝建構函式的標準寫法如下 class base base const base b 上述寫法見得最多,甚至你認為理所當然。那麼如果我們不寫成引用傳遞呢,而是值傳遞,那麼會怎樣?class base base const base b 編譯出錯 error c2652 base illegal co...
複製建構函式
呼叫複製建構函式的情形 在c 中,下面三種物件需要呼叫複製建構函式 1 乙個物件作為函式引數,以值傳遞的方式傳入函式體 2 乙個物件作為函式返回值,以值傳遞的方式從函式返回 3 乙個物件用於給另外乙個物件進行初始化 常稱為賦值初始化 4 編譯器生成臨時物件 一 乙個物件作為函式引數,以值傳遞的方式傳...