13-拷貝控制

13.1 拷貝靴迫,賦值與銷毀

以上這些操作玉锌,必須明白定義與不定義會對類的操作產生何種影響主守,變編譯器定義的合成版本未必符合類設計的初衷榄融。

13.1.1 拷貝構造函數

如果一個構造函數的第一個參數是同類型的引用,且任何其他參數都有默認值救湖,則此構造函數為拷貝構造函數。

必須是引用類型參數力九,因為在調用非引用參數的函數時,會拷貝實參舒萎,而拷貝實參又需要調用拷貝構造函數,那么會無休止的調用下去咆贬。

Foo(const Foo&);

合成拷貝構造函數會將其參數的成員(非static)逐個拷貝到正在創(chuàng)建的對象中掏缎。

直接初始化:使用普通的函數匹配,選擇參數最匹配的構造函數酌儒。

拷貝初始化:將對象或者可以轉換為相同類型的對象拷貝到正在創(chuàng)建的對象中酪夷。

1榴啸,使用=運算符定義變量

2,將對象作為實參傳遞給一個非引用類型

3狂鞋,從非引用類型返回類型的函數里返回一個對象

4要销,使用初始值列表初始化一個數組中的元素或一個聚類中的成員

13.1.2 拷貝賦值運算符

Foo& operator=(const Foo&);

如果運算符是一個成員函數,其左側對象就綁定到隱式的this參數脐供。

合成拷貝賦值運算符:將右側運算對象的每個成員(非static)賦予左側運算對象的對應成員

13.1.3 析構函數

~Foo();

在一個構造函數中政己,成員的初始化是在函數體執(zhí)行之前完成的歇由,且按照在類中出現的順序進行的果港;而在析構函數中谢谦,首先執(zhí)行函數體猩谊,然后銷毀成員,成員按初始化順序逆序銷毀。

當一個對象被銷毀時會自動調用其析構函數。當指向一個對象的引用會指針離開作用域是焰情,析構函數不會執(zhí)行。

合成析構函數:空的函數體

13.1.4 三/五法則

如果一個類需要自定義析構函數(一般是銷毀動態(tài)分配的內存),則可能也需要拷貝構造函數和拷貝賦值運算符。

需要拷貝操作的類也需要賦值操作,反之亦然谈为,但未必需要析構函數耘成。

13.1.5 使用=default

使用=default修飾拷貝控制成員榔昔,編譯器將生成相應成員的合成版本。=default在類內則隱式的聲明為內聯瘪菌。

Foo& operator=(const Foo&) = default;

Foo(const Foo&) =default撒会;

只能用來修飾具有合成版本的成員函數。

13.1.6 阻止拷貝

將拷貝構造函數和拷貝賦值運算符定義為刪除的函數來阻止拷貝师妙,即诵肛,雖然聲明了,但是不可以使用它們默穴。

Foo(const Foo&) = delete;//阻止拷貝

Foo& operator=(const Foo&) = delete;//阻止賦值

=delete必須出現在第一次聲明的時候怔檩;可以對任何函數指定=delete

對于刪除了析構函數的類型,不可以定義此類型的變量或成員蓄诽,但可以動態(tài)分配這種類型薛训,但是無法釋放它們。

合成的拷貝控制成員可能是刪除的

如果類有數據成員不能被默認構造仑氛,拷貝乙埃,賦值闸英,復制或銷毀(delete或者private修飾),則此類對應的合成成員函數被定義為刪除的介袜。(引用成員或無法默認構造的const成員)

通過聲明但不定義private的拷貝構造函數或拷貝賦值運算符甫何,試圖拷貝或賦值的操作在編譯階段被標記為錯誤;成員函數或友元函數中的拷貝或賦值會導致鏈接錯誤遇伞。(舊的方法)

13.2 拷貝控制和資源管理

管理類外的類必須定義拷貝控制成員辙喂。

13.2.1 行為像值的類

對于類管理的資源,每個對象都有一份拷貝鸠珠。

賦值操作會銷毀左側運算對象的資源巍耗,之后從右側運算對象拷貝數據,必須確保自賦值是異常安全的(可先將右側運算對象的數據拷貝到零時對象中)跳芳。

13.2.2 行為像指針的類

多個此類的對象共享同一份數據(使用智能指針或引用計數管理)

13.3 交換操作

void swap(Foo &lhs, Foo &rhs){

using std::swap;//若沒有類型自定義的swap版本芍锦,則調用std的版本

swap(lhs.h, rhs.h);//類型自定義的版本

}

拷貝并交換技術

Foo& Foo::operator=(Foo rhs){

swap(*this, rhs);

return *this;

}

參數并不是引用竹勉,在函數執(zhí)行完后會釋放飞盆。可自動處理自賦值的情況次乓,且是異常安全的吓歇。

13.6 對象移動

當一個對象拷貝后就立即銷毀,此時使用移動操作可以提高性能票腰。

標準庫容器城看,string,shared_ptr類支持移動和拷貝杏慰,IO類和unique_ptr類只支持移動测柠。

13.6.1 右值引用

即,必須綁定到右值的引用缘滥。只能綁定到將要銷毀的對象轰胁,故可以將右值引用的資源移動到另一個對象中。

一個左值表達式表示一個對象的身份朝扼,而右值表達式表示的是對象的值赃阀。

int &&r = i*42;

返回左值引用的函數,連同賦值擎颖,下標榛斯,解引用和前置遞增遞減運算符,都返回左值搂捧;

返回非引用類型的函數驮俗,連同算數,關系允跑,位以及后置遞增遞減運算符王凑,都生成右值提佣,可以用const的左值引用和右值引用綁定。

左值有持久的狀態(tài)荤崇,右值要么是字面值常量拌屏,要么是表達式求值過程中創(chuàng)建的臨時變量。

右值意味著:該對象將被銷毀术荤;該對象沒有其他用戶倚喂。故使用右值引用的代碼可以自由的接管引用的對象的資源。

int &&rr1 = 42;

int &&rr2 = rr1;//錯誤:rr1是右值引用類型的變量瓣戚,是左值

#include <utility>

int &&rr3 ?=std::move(rr1);//move函數獲得綁定到左值上的右值引用端圈。

move意味著希望像處理右值一樣處理一個左值,即子库,除了對rr1賦值和銷毀外舱权,代碼不會再使用它。

13.6.2 移動構造函數和移動賦值運算符

從給定對象“竊取”而不是拷貝資源仑嗅。

移動拷貝構造函數第一個參數是該類類型的右值引用宴倍,其他的參數必須都具有默認實參。

StrVec::StrVec(StrVec &&s) noexcept:e(s.e), f(s.f){s.e = s.f = nullptr;}

1仓技,移動操作不應該拋出異常鸵贬,noexcept通知標準庫移動操作是安全的的,無需標準庫做額外的操作

2脖捻,成員初始化器中接管s中的資源

3阔逼,函數體中使對s進行析構是安全的

noexcept在聲明和定義中都需要指定。

StrVec &StrVec::operator=(StrVec &&rhs) noexcept{}

在移動操作之后地沮,移后源對象必須保持有效的嗜浮,可析構的狀態(tài),但用戶不可對其值進行任何假設摩疑。

當一個類沒有定義任何自己版本的拷貝控制成員危融,且類的每個非static數據成員都可以移動時,編譯器才會合成移動構造函數或移動賦值運算符未荒。

可以移動:內置類型专挪,類類型定義了相應的移動操作。

移動操作不會隱式的定義為刪除的函數片排,但顯式定義=default的移動操作寨腔,且編譯器不能移動所有成員,則編譯器將移動操作定義為刪除的函數率寡。

如果類定義了一個移動構造函數或一個移動賦值運算符迫卢,則該類的合成拷貝構造函數和拷貝賦值運算符會被定義為刪除的。

如果一個類既有移動構造函數冶共,又有拷貝構造函數乾蛤,則使用普通的函數匹配規(guī)則來選擇調用每界。如果沒有移動構造函數或移動賦值運算符,右值會被拷貝家卖。

移動迭代器

移動迭代器的解引用運算符生成一個右值引用眨层,make_move_iterator(origin_iterator);函數將普通的迭代器轉換為一個移動迭代器,會調用相應的西東構造函數或移動賦值運算符操作上荡。

13.6.3 右值引用和成員函數

成員函數提供移動版本:

void push_back(const X&);//拷貝

void push_back(X&&);//移動

引用限定符

Foo &operator=(const Foo&) &;//只能向可修改的左值賦值

引用限定符可以是&和&&趴樱,分別指出this可以指向一個左值或右值,只能用于非static的成員函數酪捡,且必須同時出現在聲明和定義中叁征。

一個函數可以同時用const和引用限定,但引用限定符必須跟隨在const之后逛薇。

引用限定符可以區(qū)分重載版本捺疼,并且可以和const綜合起來區(qū)分。

當定義多個具有相同名字和相同參數列表的成員函數時永罚,必須所有函數都加上引用限定符或都不加啤呼。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市尤蛮,隨后出現的幾起案子媳友,更是在濱河造成了極大的恐慌斯议,老刑警劉巖产捞,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異哼御,居然都是意外死亡坯临,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進店門恋昼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來看靠,“玉大人,你說我怎么就攤上這事液肌⌒妫” “怎么了?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵嗦哆,是天一觀的道長谤祖。 經常有香客問我,道長老速,這世上最難降的妖魔是什么粥喜? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮橘券,結果婚禮上额湘,老公的妹妹穿的比我還像新娘卿吐。我一直安慰自己,他們只是感情好锋华,可當我...
    茶點故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布嗡官。 她就那樣靜靜地躺著,像睡著了一般毯焕。 火紅的嫁衣襯著肌膚如雪谨湘。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天芥丧,我揣著相機與錄音紧阔,去河邊找鬼。 笑死续担,一個胖子當著我的面吹牛擅耽,可吹牛的內容都是我干的。 我是一名探鬼主播物遇,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼乖仇,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了询兴?” 一聲冷哼從身側響起乃沙,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎诗舰,沒想到半個月后警儒,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡眶根,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年蜀铲,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片属百。...
    茶點故事閱讀 37,989評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡记劝,死狀恐怖,靈堂內的尸體忽然破棺而出族扰,到底是詐尸還是另有隱情厌丑,我是刑警寧澤,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布渔呵,位于F島的核電站怒竿,受9級特大地震影響,放射性物質發(fā)生泄漏厘肮。R本人自食惡果不足惜愧口,卻給世界環(huán)境...
    茶點故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望类茂。 院中可真熱鬧耍属,春花似錦托嚣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至领舰,卻和暖如春夫嗓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背冲秽。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工舍咖, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人锉桑。 一個月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓排霉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親民轴。 傳聞我的和親對象是個殘疾皇子攻柠,可洞房花燭夜當晚...
    茶點故事閱讀 42,700評論 2 345

推薦閱讀更多精彩內容