iT邦幫忙

2023 iThome 鐵人賽

DAY 16
0
自我挑戰組

Effective C++ 讀書筆記系列 第 16

[Day 16] Handle assignment to self in operator= (2)

  • 分享至 

  • xImage
  •  

前言

接續昨日([Day 15] Handle assignment to self in operator= (1))內容,我們看到需要確保self-assignment-safe,並且可以以identity test來實現,那還有沒有其它要注意的地方或其他作法呢?

調整寫法順序,確保exception-safe兩者兼得!

昨天的改法,雖然確保了self-assignment-safe,但卻沒有避免 exception-unsafe
new Bitmap報exception的時候(可能memory不足,或Bitmap自己本身的copy constructor報exception),仍有可能變成讓Widgetpb指向一個被刪除的物件。這會有什麼後果呢?我們根本不能正常使用它!
值得慶幸的是如果我們能確保exception-safe,它通常也能連帶保證self-assignment-safe,所以大家通常直接專注於確保exception-safe,這個在後面的守則會有更深入的介紹,而在目前,我們可以觀察到用一些順序調整,來達到exception-safe的效果:

Widget& Widget::operator=(const Widget& rhs)
{
    Bitmap *pOrig = pb;
    pb = new Bitmap(*rhs.pb);
    delete pOrig;
    return *this;
}

可以看到這邊的做法是先做一個原本bitmap的copy並指向它,之後指向新的成功之後才去刪除原本的bitmap,所以就算new的過程中出現exception也沒事;而此時如果回到assign給自己的情況,也沒有問題。
此時,可能會覺得雖然assign給自己沒問題,但多了無謂的操作(先copy再指回去再刪除),沒有效率,那也可以再把identity test加回去;然而,我們在考慮最有效的寫法時,應該也要思考這個情形出現的頻率,因為identity test也是有代價的,code變多了,flow變複雜了,這都可能會降低runtime的速度,也有可能降低code base變大複雜度變高一系列的負面影響。

copy and swap!

還有一種確保exception跟self-assignment-sage的方法,就是採用 "copy and swap"。這個同樣會在後面詳細介紹,但因為這個做法很常見,我們可以先看看它通常怎麼做就好:

class Widget
{
   void swap(Widget& rhs); // exchange *this and rhs data
}

Widget& Widget::Operator=(const Widget& rhs)
{
    Widget temp(rhs); // make a copy of rhs's data
    swap(temp); // swap *this data with the copy data
    return *this;
}

它有一種變形的寫法長這樣:

Widget& Widgget::operator=(Widget rhs)
{
    swap(rhs);
    return *this;
}

這利用了copy assignment 也可以被宣告為take argument by value,又by value的時候就會make a copy的特性,直接一行搞定!這種寫法讓copy的步驟從function body移到了parameter的construction,可能可以編譯出更有效率的code。

總結

貼心重點提醒:

  • Make sure that any function operating on more than one object behaves correctly if two or more of the objects are the same
  • Make sure operator= is well-behaved when an object is assigned to itself. Techniques include comparing addresses of source and target objects, careful statement ordering, and copy-and-swap.

總結要確保self-assignment-safe的常見左法有三種:1. identity test, 2. 調整寫法 3. copy-and-swap;如果self-assigment 發生頻率不高,我們可以專注於確保exception-safe即可。


上一篇
[Day 15] Handle assignment to self in operator= (1)
下一篇
[Day 17] Copy all parts of an object (1)
系列文
Effective C++ 讀書筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言