精華區beta C_and_CPP 關於我們 聯絡資訊
我換了一個新的帳號: gocpp -> cppOrz 因為新的帳號實在是太可愛了! 這篇的內容是有關 operator overloading 設計的觀念 假如有個 class Point 如下: struct Point { Point(int a=0, int b=0) : x(a), y(b) {} int x, y; }; 現在想替它寫個 operator+ 運算子,該怎麼辦呢? Point const Point::operator+(Point const &rhs) // 版本 A0 { return Point(x+rhs.x, y+rhs.y); } 版本 A0 是常見的作法,但是它其實不太好,有兩個主要的缺點。 一個是介面設計上的,一個是實作方法上的。首先看介面設計的 問題,把 operator+ 當作成員函式的話,+ 號的左邊就不能隱式 轉型,也就是如果某個型別 T 可以隱式轉型成 Point 的話,那 就會出現下面的狀況: Point p1; T p2; Point p; p = p1 + p2; // ok, 沒問題 p = p2 + p1; // 喔噢,編譯不過。 通常的情況, 加法運算應該是要滿足交換率的。至少 C/C++ 的內建 型別無不如此。但這種設計卻不符合需求,因此必須改良一下。 Point const operator+(Point const &lhs, Point const &rhs) // 版本 A1 { return Point(lhs.x+rhs.x, lhs.y+rhs.y); } 把 operator+ 這種二元運算,設為 namespace 層級(而非 class 成員)的函式,是 C++ 函式介面設計的基本觀念,大家如果有注意到 的話,看一下 std::complex<T> 的介面,它就是這樣設計的。這樣不 論左邊或右邊兩個參數都允許隱式轉型。 我印象中 C# 的 operator overloading 介面,就和 C++ 不同,例如 它的 operator+,這種二元運算,仍是設計為成員函式,而且還會幫用 戶自動產生相關的運算,產生規則和實作的方式也和 C++ 標準的做法 不同。 版本 A1 的介面雖然理想了,但它的實作方式卻仍然存在缺陷。原因是, 如果我們想要替 class Point 增加一個 operator+= 的成員,那該怎 麼辦呢? Point &Point::operator+=(Point const &rhs) // 版本 B1 { return *this = *this + rhs; // 利用版本 A1 } 初看起來它很完美,沒有什麼問題,但實際上這種設計在 C++ 中可能會 造成效率的損失。原因在於 operator+= 回傳的是 reference to *this, 但其中的過程卻是呼叫了 operator+,而 operator+ 回傳的是物件,也 就是經過了一次不必要的物件複製的動作。(我印象中,C# 自動生成的 程式碼就是類似這樣做的,不過不同的是,C# 有內建 GC,回傳值可以用 new的,不必擔心物件複製的問題。)因為本來 operator+= 完全是不需 要物件複製的: Point &Point::operator+=(Point const &rhs) // 版本 B2 { x += rhs.x; y += rhs.y; return *this; } 可以看出,版本 B1 的實作,多了一次不必要的物件複製,而且由於 它是將結果存到 *this 中,RVO(回傳值優化)的編譯器技術也無用 武之地。像 class Point 這樣的小東西,多產生一個暫時物件的差 別幾乎可以視而不見,但若是某些大型架構,例如多維的 Matrix 運算,而且是大量的頻繁使用時,每次多一個暫時物件,整體效率的 損失就很可觀了。 因此,正確的實作法應該是以 operator+= 來實現 operator+ Point const operator+(Point const &lhs, Point const &rhs) // 版本 A2 { return Point(lhs) += rhs; // 利用版本 B2 } 另外,以上的例子,也告訴我們一件事,就是以下兩種寫法: Point a, b, c, d; Point p1 = a + b + c + d; Point p2 = a; p2 += b; p2 += c; p2 += d; 使用 p2 的方式,會比 p1 來得有效率,所以如果有嚴格的效率 要求時,最好多用 p2 的寫法。 兩個重點: 一、關於介面,不要把 operator+ 設計為成員函式,它應該是個  namespace 函式 二、關於實作,請以 operator+= 來實現 operator+(不要倒過來),  因為後者多了一次物件複製。 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 59.120.214.120
renderer:推 Orz大實在太熱心了 61.222.148.171 08/23
renderer:另外 cppOrz 唸起來真是帥呀 XD 61.222.148.171 08/23
renderer:cppOrz 看起來也是很可愛 XD 61.222.148.171 08/23
renderer:真有你的 呵呵 61.222.148.171 08/23
FRAXIS:A0版本最好可以加上const 不然常數不能加 140.119.162.51 08/23
FRAXIS:return by value 不一定需要加上const 140.119.162.51 08/23
khoguan:改取了這種id,舒緩了您嚴謹深入的高人風貌 :-)220.130.208.168 08/23
drkkimo:@@? 218.164.26.249 08/23
drkkimo:我覺得分析的很詳細 多幾篇這類的探討真不錯 218.164.26.249 08/23
sekya:好文 必推一下 59.104.35.45 08/25
> -------------------------------------------------------------------------- < 作者: renderer (rendering) 看板: C_and_CPP 標題: Re: [心得] operator+ 與 operator+= 的設計 時間: Tue Aug 23 12:00:41 2005 ※ 引述《cppOrz (cppOrz)》之銘言: : Point const operator+(Point const &lhs, Point const &rhs) // 版本 A1 : { : return Point(lhs.x+rhs.x, lhs.y+rhs.y); : } : Point const operator+(Point const &lhs, Point const &rhs) // 版本 A2 : { : return Point(lhs) += rhs; // 利用版本 B2 : } 敢問 cppOrz 大 版本 A1 與 A2 是否有效能上的差異呢 ------------------------------------------------ cpp Orz - 面對 cpp Orz 太可愛了 呵呵 別打我 ... -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 61.222.148.171 ※ 編輯: renderer 來自: 61.222.148.171 (08/23 12:02)
cppOrz:這可考倒我了,我覺得應該是一樣啦,就算有差也 59.120.214.120 08/23
cppOrz:差不到哪裏去。不過利用 += 的實作是維持一致性 59.120.214.120 08/23
cppOrz:的原則,應該比較好。 59.120.214.120 08/23
> -------------------------------------------------------------------------- < 作者: khoguan (Khoguan Phuann) 看板: C_and_CPP 標題: Re: [心得] operator+ 與 operator+= 的設計 時間: Tue Aug 23 13:02:53 2005 ※ 引述《renderer (rendering)》之銘言: : ※ 引述《cppOrz (cppOrz)》之銘言: : : Point const operator+(Point const &lhs, Point const &rhs) // 版本 A1 : : { : : return Point(lhs.x+rhs.x, lhs.y+rhs.y); : : } : : Point const operator+(Point const &lhs, Point const &rhs) // 版本 A2 : : { : : return Point(lhs) += rhs; // 利用版本 B2 : : } : 敢問 cppOrz 大 : 版本 A1 與 A2 是否有效能上的差異呢 : → cppOrz:這可考倒我了,我覺得應該是一樣啦,就算有差也 59.120.214.120 08/23 : → cppOrz:差不到哪裏去。不過利用 += 的實作是維持一致性 59.120.214.120 08/23 : → cppOrz:的原則,應該比較好。 59.120.214.120 08/23 除了 cppOrz大大的推文說明外,我想,版本A1有個大問題是, 它往往要指定成 friend function 才能存取到 Point class的 private data member, 雖然很多時候,像是 Point 這種 class, 都會提供 public 的 getter member function, 但也有其他時候 是沒有提供的。而版本 A2 利用既有的public operator+= 來實作 operator+ 就可完全避免這種問題。所以不但維持了一致性,也可 保有較佳的封裝性。 題外話,在幾何上「兩點相加」這樣的概念存在嗎?可以表示位移嗎? -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 220.130.208.168
cppOrz:兩點相加當然是沒有的,但是 (x,y) 數對除了可以 59.120.214.120 08/23
cppOrz:看成一個點之外,也可以看成一個向量,所以加法 59.120.214.120 08/23
cppOrz:仍是有用的。不過我主要是示範用偷懶的例子啦 59.120.214.120 08/23
cppOrz:另外,如果必要的話,設成 friend 算正常的。 59.120.214.120 08/23
> -------------------------------------------------------------------------- < 作者: renderer (rendering) 看板: C_and_CPP 標題: Re: [心得] operator+ 與 operator+= 的設計 時間: Tue Aug 23 14:36:56 2005 ※ 引述《renderer (rendering)》之銘言: : 標題: Re: [心得] operator+ 與 operator+= 的設計 : 時間: Tue Aug 23 12:00:41 2005 : ※ 引述《cppOrz (cppOrz)》之銘言: : : Point const operator+(Point const &lhs, Point const &rhs) // 版本 A1 : : { : : return Point(lhs.x+rhs.x, lhs.y+rhs.y); : : } : : Point const operator+(Point const &lhs, Point const &rhs) // 版本 A2 : : { : : return Point(lhs) += rhs; // 利用版本 B2 : : } : 敢問 cppOrz 大 : 版本 A1 與 A2 是否有效能上的差異呢 : : -- : ※ 發信站: 批踢踢實業坊(ptt.cc) : ◆ From: 61.222.148.171 : ※ 編輯: renderer 來自: 61.222.148.171 (08/23 12:02) : → cppOrz:這可考倒我了,我覺得應該是一樣啦,就算有差也 59.120.214.120 08/23 : → cppOrz:差不到哪裏去。不過利用 += 的實作是維持一致性 59.120.214.120 08/23 : → cppOrz:的原則,應該比較好。 59.120.214.120 08/23 其實我真正想問的是 A2 版本的 RVO 是否仍然會作用 A2 版本如果 RV0 沒有作用 就會多一次物件建構的成本了 當然 這種效能上的差異是雞蛋裏挑骨頭 我有試了一下 struct Vector { float x,y,z }; 在兩個實作間的效能差異 似乎 A2 會比較慢些 (GCC 最佳化全開) 另外問一個問題是: 一個 inline 函式裏又呼叫了另一個 inline 函式 編譯器是否會捨棄 inline 呢 會以什麼為決擇依據呢 感謝 :) -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 61.222.148.171
renderer:嘿嘿 在沒有新手發問的時候 多跟高手們討點寶 61.222.148.171 08/23
> -------------------------------------------------------------------------- < 作者: FRAXIS (喔喔) 看板: C_and_CPP 標題: Re: [心得] operator+ 與 operator+= 的設計 時間: Tue Aug 23 16:03:15 2005 ※ 引述《cppOrz (cppOrz)》之銘言: : 其實我一般是不加 const 的,不過 Effective C++ 系列中把回傳值加上 : 了 const,所以就照著寫。書上的理由是,如果不加 const,以下的寫法 : 是可以通過編譯的: : : Point a, b, c; : (a+b) = c; // 竟然可以這樣寫! : : 加上 const 就不會有這種問題了。 : : -- : ※ 發信站: 批踢踢實業坊(ptt.cc) : ◆ From: 59.120.214.120 : 推 jeunder:你誤會他的意思了, 他是說 operator+ function 61.64.150.151 08/23 : → jeunder:最好要設成 const function... 61.64.150.151 08/23 : → jeunder:否則面對 const instance 時, 無法加起來... 61.64.150.151 08/23 : → cppOrz:感謝指正。我從來不寫 A0 版本所以沒注意到這問 59.120.214.120 08/23 : → cppOrz:題,不過 return const 物件是照書上的說明 59.120.214.120 08/23 cppOrz大大沒有誤會我的意思啦,因為我兩句推文分別講兩件事情 ,分別是const function和return const的事情。 我可以理解Effective C++作者的想法(a+b) = c是件很怪的事情。 但是如果有一個成員函式f,他並非const的成員函式,假使return value 非const的話,我可以這樣寫 Point t1, t2, t3, t4; Point t3 = (t1 + t2).f() + (t3 + t4).f(); 然而假使return value是const的話,寫起來就比較麻煩。 這沒有什麼對錯的問題,只是設計理念和習慣問題而已.. -- 我記得好像Herb Sutter的新書有討論到這問題,有人有印象嘛? -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 61.229.34.163
jeunder:對於 const instance 施行 nonconst mem. func. 61.64.150.151 08/23
jeunder:根本就是件很奇怪的事情... 61.64.150.151 08/23
> -------------------------------------------------------------------------- < 作者: UNARYvvv (有趣生活) 看板: C_and_CPP 標題: Re: [心得] operator+ 與 operator+= 的設計 時間: Wed Aug 24 12:57:35 2005 ※ 引述《renderer (rendering)》之銘言: : ※ 引述《renderer (rendering)》之銘言: : : 標題: Re: [心得] operator+ 與 operator+= 的設計 : : 時間: Tue Aug 23 12:00:41 2005 : : 敢問 cppOrz 大 : : 版本 A1 與 A2 是否有效能上的差異呢 : : -- : : ◆ From: 61.222.148.171 : : → cppOrz:這可考倒我了,我覺得應該是一樣啦,就算有差也 59.120.214.120 08/23 : : → cppOrz:差不到哪裏去。不過利用 += 的實作是維持一致性 59.120.214.120 08/23 : : → cppOrz:的原則,應該比較好。 59.120.214.120 08/23 : 其實我真正想問的是 A2 版本的 RVO 是否仍然會作用 ^喔? : A2 版本如果 RV0 沒有作用 就會多一次物件建構的成本了 ^零!? r大..我彷彿看見了你的惡搞XDD -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 61.70.137.117
renderer:o.O 61.222.148.171 08/24
ledia:怎麼會看出來 @_@? 話說 O 和 0 是會打錯的 XD 140.112.30.55 08/24
renderer:U大 您不會連 BBS 都用 Programming Font 吧 XD 61.222.148.171 08/24
renderer:0.0 O.O 61.222.148.171 08/24
UNARYvvv:我是用 PCMan 原本設定啊..細明體囉~ 61.70.137.117 08/24
renderer:那 U大眼力好 61.222.148.171 08/24
> -------------------------------------------------------------------------- < 作者: cppOrz (cppOrz) 看板: C_and_CPP 標題: [心得] operator+ 與 operator+= 的設計 時間: Tue Aug 23 11:30:26 2005 我換了一個新的帳號: gocpp -> cppOrz 因為新的帳號實在是太可愛了! 這篇的內容是有關 operator overloading 設計的觀念 假如有個 class Point 如下: struct Point { Point(int a=0, int b=0) : x(a), y(b) {} int x, y; }; 現在想替它寫個 operator+ 運算子,該怎麼辦呢? Point const Point::operator+(Point const &rhs) // 版本 A0 { return Point(x+rhs.x, y+rhs.y); } 版本 A0 是常見的作法,但是它其實不太好,有兩個主要的缺點。 一個是介面設計上的,一個是實作方法上的。首先看介面設計的 問題,把 operator+ 當作成員函式的話,+ 號的左邊就不能隱式 轉型,也就是如果某個型別 T 可以隱式轉型成 Point 的話,那 就會出現下面的狀況: Point p1; T p2; Point p; p = p1 + p2; // ok, 沒問題 p = p2 + p1; // 喔噢,編譯不過。 通常的情況, 加法運算應該是要滿足交換率的。至少 C/C++ 的內建 型別無不如此。但這種設計卻不符合需求,因此必須改良一下。 Point const operator+(Point const &lhs, Point const &rhs) // 版本 A1 { return Point(lhs.x+rhs.x, lhs.y+rhs.y); } 把 operator+ 這種二元運算,設為 namespace 層級(而非 class 成員)的函式,是 C++ 函式介面設計的基本觀念,大家如果有注意到 的話,看一下 std::complex<T> 的介面,它就是這樣設計的。這樣不 論左邊或右邊兩個參數都允許隱式轉型。 我印象中 C# 的 operator overloading 介面,就和 C++ 不同,例如 它的 operator+,這種二元運算,仍是設計為成員函式,而且還會幫用 戶自動產生相關的運算,產生規則和實作的方式也和 C++ 標準的做法 不同。 版本 A1 的介面雖然理想了,但它的實作方式卻仍然存在缺陷。原因是, 如果我們想要替 class Point 增加一個 operator+= 的成員,那該怎 麼辦呢? Point &Point::operator+=(Point const &rhs) // 版本 B1 { return *this = *this + rhs; // 利用版本 A1 } 初看起來它很完美,沒有什麼問題,但實際上這種設計在 C++ 中可能會 造成效率的損失。原因在於 operator+= 回傳的是 reference to *this, 但其中的過程卻是呼叫了 operator+,而 operator+ 回傳的是物件,也 就是經過了一次不必要的物件複製的動作。(我印象中,C# 自動生成的 程式碼就是類似這樣做的,不過不同的是,C# 有內建 GC,回傳值可以用 new的,不必擔心物件複製的問題。)因為本來 operator+= 完全是不需 要物件複製的: Point &Point::operator+=(Point const &rhs) // 版本 B2 { x += rhs.x; y += rhs.y; return *this; } 可以看出,版本 B1 的實作,多了一次不必要的物件複製,而且由於 它是將結果存到 *this 中,RVO(回傳值優化)的編譯器技術也無用 武之地。像 class Point 這樣的小東西,多產生一個暫時物件的差 別幾乎可以視而不見,但若是某些大型架構,例如多維的 Matrix 運算,而且是大量的頻繁使用時,每次多一個暫時物件,整體效率的 損失就很可觀了。 因此,正確的實作法應該是以 operator+= 來實現 operator+ Point const operator+(Point const &lhs, Point const &rhs) // 版本 A2 { return Point(lhs) += rhs; // 利用版本 B2 } 另外,以上的例子,也告訴我們一件事,就是以下兩種寫法: Point a, b, c, d; Point p1 = a + b + c + d; Point p2 = a; p2 += b; p2 += c; p2 += d; 使用 p2 的方式,會比 p1 來得有效率,所以如果有嚴格的效率 要求時,最好多用 p2 的寫法。 兩個重點: 一、關於介面,不要把 operator+ 設計為成員函式,它應該是個  namespace 函式 二、關於實作,請以 operator+= 來實現 operator+(不要倒過來),  因為後者多了一次物件複製。 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 59.120.214.120
renderer:推 Orz大實在太熱心了 61.222.148.171 08/23
renderer:另外 cppOrz 唸起來真是帥呀 XD 61.222.148.171 08/23
renderer:cppOrz 看起來也是很可愛 XD 61.222.148.171 08/23
renderer:真有你的 呵呵 61.222.148.171 08/23
FRAXIS:A0版本最好可以加上const 不然常數不能加 140.119.162.51 08/23
FRAXIS:return by value 不一定需要加上const 140.119.162.51 08/23
khoguan:改取了這種id,舒緩了您嚴謹深入的高人風貌 :-)220.130.208.168 08/23
drkkimo:@@? 218.164.26.249 08/23
drkkimo:我覺得分析的很詳細 多幾篇這類的探討真不錯 218.164.26.249 08/23
sekya:好文 必推一下 59.104.35.45 08/25
> -------------------------------------------------------------------------- < 作者: renderer (rendering) 看板: C_and_CPP 標題: Re: [心得] operator+ 與 operator+= 的設計 時間: Tue Aug 23 12:00:41 2005 ※ 引述《cppOrz (cppOrz)》之銘言: : Point const operator+(Point const &lhs, Point const &rhs) // 版本 A1 : { : return Point(lhs.x+rhs.x, lhs.y+rhs.y); : } : Point const operator+(Point const &lhs, Point const &rhs) // 版本 A2 : { : return Point(lhs) += rhs; // 利用版本 B2 : } 敢問 cppOrz 大 版本 A1 與 A2 是否有效能上的差異呢 ------------------------------------------------ cpp Orz - 面對 cpp Orz 太可愛了 呵呵 別打我 ... -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 61.222.148.171 ※ 編輯: renderer 來自: 61.222.148.171 (08/23 12:02)
cppOrz:這可考倒我了,我覺得應該是一樣啦,就算有差也 59.120.214.120 08/23
cppOrz:差不到哪裏去。不過利用 += 的實作是維持一致性 59.120.214.120 08/23
cppOrz:的原則,應該比較好。 59.120.214.120 08/23
> -------------------------------------------------------------------------- < 作者: khoguan (Khoguan Phuann) 看板: C_and_CPP 標題: Re: [心得] operator+ 與 operator+= 的設計 時間: Tue Aug 23 13:02:53 2005 ※ 引述《renderer (rendering)》之銘言: : ※ 引述《cppOrz (cppOrz)》之銘言: : : Point const operator+(Point const &lhs, Point const &rhs) // 版本 A1 : : { : : return Point(lhs.x+rhs.x, lhs.y+rhs.y); : : } : : Point const operator+(Point const &lhs, Point const &rhs) // 版本 A2 : : { : : return Point(lhs) += rhs; // 利用版本 B2 : : } : 敢問 cppOrz 大 : 版本 A1 與 A2 是否有效能上的差異呢 : → cppOrz:這可考倒我了,我覺得應該是一樣啦,就算有差也 59.120.214.120 08/23 : → cppOrz:差不到哪裏去。不過利用 += 的實作是維持一致性 59.120.214.120 08/23 : → cppOrz:的原則,應該比較好。 59.120.214.120 08/23 除了 cppOrz大大的推文說明外,我想,版本A1有個大問題是, 它往往要指定成 friend function 才能存取到 Point class的 private data member, 雖然很多時候,像是 Point 這種 class, 都會提供 public 的 getter member function, 但也有其他時候 是沒有提供的。而版本 A2 利用既有的public operator+= 來實作 operator+ 就可完全避免這種問題。所以不但維持了一致性,也可 保有較佳的封裝性。 題外話,在幾何上「兩點相加」這樣的概念存在嗎?可以表示位移嗎? -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 220.130.208.168
cppOrz:兩點相加當然是沒有的,但是 (x,y) 數對除了可以 59.120.214.120 08/23
cppOrz:看成一個點之外,也可以看成一個向量,所以加法 59.120.214.120 08/23
cppOrz:仍是有用的。不過我主要是示範用偷懶的例子啦 59.120.214.120 08/23
cppOrz:另外,如果必要的話,設成 friend 算正常的。 59.120.214.120 08/23
> -------------------------------------------------------------------------- < 作者: renderer (rendering) 看板: C_and_CPP 標題: Re: [心得] operator+ 與 operator+= 的設計 時間: Tue Aug 23 14:36:56 2005 ※ 引述《renderer (rendering)》之銘言: : 標題: Re: [心得] operator+ 與 operator+= 的設計 : 時間: Tue Aug 23 12:00:41 2005 : ※ 引述《cppOrz (cppOrz)》之銘言: : : Point const operator+(Point const &lhs, Point const &rhs) // 版本 A1 : : { : : return Point(lhs.x+rhs.x, lhs.y+rhs.y); : : } : : Point const operator+(Point const &lhs, Point const &rhs) // 版本 A2 : : { : : return Point(lhs) += rhs; // 利用版本 B2 : : } : 敢問 cppOrz 大 : 版本 A1 與 A2 是否有效能上的差異呢 : : -- : ※ 發信站: 批踢踢實業坊(ptt.cc) : ◆ From: 61.222.148.171 : ※ 編輯: renderer 來自: 61.222.148.171 (08/23 12:02) : → cppOrz:這可考倒我了,我覺得應該是一樣啦,就算有差也 59.120.214.120 08/23 : → cppOrz:差不到哪裏去。不過利用 += 的實作是維持一致性 59.120.214.120 08/23 : → cppOrz:的原則,應該比較好。 59.120.214.120 08/23 其實我真正想問的是 A2 版本的 RVO 是否仍然會作用 A2 版本如果 RV0 沒有作用 就會多一次物件建構的成本了 當然 這種效能上的差異是雞蛋裏挑骨頭 我有試了一下 struct Vector { float x,y,z }; 在兩個實作間的效能差異 似乎 A2 會比較慢些 (GCC 最佳化全開) 另外問一個問題是: 一個 inline 函式裏又呼叫了另一個 inline 函式 編譯器是否會捨棄 inline 呢 會以什麼為決擇依據呢 感謝 :) -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 61.222.148.171
renderer:嘿嘿 在沒有新手發問的時候 多跟高手們討點寶 61.222.148.171 08/23
> -------------------------------------------------------------------------- < 作者: FRAXIS (喔喔) 看板: C_and_CPP 標題: Re: [心得] operator+ 與 operator+= 的設計 時間: Tue Aug 23 16:03:15 2005 ※ 引述《cppOrz (cppOrz)》之銘言: : 其實我一般是不加 const 的,不過 Effective C++ 系列中把回傳值加上 : 了 const,所以就照著寫。書上的理由是,如果不加 const,以下的寫法 : 是可以通過編譯的: : : Point a, b, c; : (a+b) = c; // 竟然可以這樣寫! : : 加上 const 就不會有這種問題了。 : : -- : ※ 發信站: 批踢踢實業坊(ptt.cc) : ◆ From: 59.120.214.120 : 推 jeunder:你誤會他的意思了, 他是說 operator+ function 61.64.150.151 08/23 : → jeunder:最好要設成 const function... 61.64.150.151 08/23 : → jeunder:否則面對 const instance 時, 無法加起來... 61.64.150.151 08/23 : → cppOrz:感謝指正。我從來不寫 A0 版本所以沒注意到這問 59.120.214.120 08/23 : → cppOrz:題,不過 return const 物件是照書上的說明 59.120.214.120 08/23 cppOrz大大沒有誤會我的意思啦,因為我兩句推文分別講兩件事情 ,分別是const function和return const的事情。 我可以理解Effective C++作者的想法(a+b) = c是件很怪的事情。 但是如果有一個成員函式f,他並非const的成員函式,假使return value 非const的話,我可以這樣寫 Point t1, t2, t3, t4; Point t3 = (t1 + t2).f() + (t3 + t4).f(); 然而假使return value是const的話,寫起來就比較麻煩。 這沒有什麼對錯的問題,只是設計理念和習慣問題而已.. -- 我記得好像Herb Sutter的新書有討論到這問題,有人有印象嘛? -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 61.229.34.163
jeunder:對於 const instance 施行 nonconst mem. func. 61.64.150.151 08/23
jeunder:根本就是件很奇怪的事情... 61.64.150.151 08/23
> -------------------------------------------------------------------------- < 作者: UNARYvvv (有趣生活) 看板: C_and_CPP 標題: Re: [心得] operator+ 與 operator+= 的設計 時間: Wed Aug 24 12:57:35 2005 ※ 引述《renderer (rendering)》之銘言: : ※ 引述《renderer (rendering)》之銘言: : : 標題: Re: [心得] operator+ 與 operator+= 的設計 : : 時間: Tue Aug 23 12:00:41 2005 : : 敢問 cppOrz 大 : : 版本 A1 與 A2 是否有效能上的差異呢 : : -- : : ◆ From: 61.222.148.171 : : → cppOrz:這可考倒我了,我覺得應該是一樣啦,就算有差也 59.120.214.120 08/23 : : → cppOrz:差不到哪裏去。不過利用 += 的實作是維持一致性 59.120.214.120 08/23 : : → cppOrz:的原則,應該比較好。 59.120.214.120 08/23 : 其實我真正想問的是 A2 版本的 RVO 是否仍然會作用 ^喔? : A2 版本如果 RV0 沒有作用 就會多一次物件建構的成本了 ^零!? r大..我彷彿看見了你的惡搞XDD -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 61.70.137.117
renderer:o.O 61.222.148.171 08/24
ledia:怎麼會看出來 @_@? 話說 O 和 0 是會打錯的 XD 140.112.30.55 08/24
renderer:U大 您不會連 BBS 都用 Programming Font 吧 XD 61.222.148.171 08/24
renderer:0.0 O.O 61.222.148.171 08/24
UNARYvvv:我是用 PCMan 原本設定啊..細明體囉~ 61.70.137.117 08/24
renderer:那 U大眼力好 61.222.148.171 08/24
> -------------------------------------------------------------------------- < 作者: cppOrz (cppOrz) 看板: C_and_CPP 標題: [心得] oprator+ 兩種版本效能測試報告 時間: Wed Aug 24 09:17:55 2005 為了驗證 operator+ 的實作效能,特別寫了幾段小程式測試 struct X { int val[1000]; X &operator+=(X const &rhs) { for (int i=0; i<1000; ++i) { val[i] += rhs.val[i]; } return *this; } }; X const operator+(X const &lhs, X const &rhs) // 版本 X1 { return X(lhs) += rhs; } X const operator+(X const &lhs, X const &rhs) // 版本 X2 { X t; for (int i=0; i<1000; ++i) { t.val[i] = lhs.val[i] + rhs.val[i]; } return t; } void Test1() // 測試程式,做 20 萬次加法運算 { for (int i=0; i<200000; ++i) { X a, b, c; c = a+b; } } 平均執行效率如下:(以下時間單位為 Ticks) 版本 X1 版本 X2 VC6(D) 3390 2578 VC6(R) 1250 750 g++3.4.2(D) 1984 1891 BCC5.6.4(D) 1394 1594 BCC5.6.4(R) 672 690 其中(D) 是 Debug 版,(R)是 Release 版,但我想還是以 Debug 版為主, 因為 Release 版做的一些優化說不定把某些動作省略了。 所以主要比較的還是 X1 和 X2 之間的差距,VC 的結果是 X2 明顯優勢, BCC是 X1 優勢,g++ 是差不多,X2 稍好。也就是說 VC6 的 RVO 技術可 能做得不是挺好才會這樣(因為即使 Release 版也是 X2 明顯優勢) 又,感覺 BCB 的 RVO 是最厲害的,對暫時物件的優化處理向來是 Borland 的專長。 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 59.120.214.120 ※ 編輯: cppOrz 來自: 59.120.214.120 (08/24 09:19)
renderer:感謝 cppOrz 的測試 61.222.148.171 08/24
※ 編輯: cppOrz 來自: 59.120.214.120 (08/24 10:10) > -------------------------------------------------------------------------- < 作者: khoguan (Khoguan Phuann) 看板: C_and_CPP 標題: Re: [心得] oprator+ 兩種版本效能測試報告 時間: Wed Aug 24 10:19:52 2005 ※ 引述《cppOrz (cppOrz)》之銘言: : 為了驗證 operator+ 的實作效能,特別寫了幾段小程式測試 [...] : X const operator+(X const &lhs, X const &rhs) // 版本 X1 : { : return X(lhs) += rhs; : } : X const operator+(X const &lhs, X const &rhs) // 版本 X2 : { : X t; : for (int i=0; i<1000; ++i) { t.val[i] = lhs.val[i] + rhs.val[i]; } : return t; : } : void Test1() // 測試程式,做 20 萬次加法運算 : { : for (int i=0; i<200000; ++i) { X a, b, c; c = a+b; } 要測 RVO 的話,可能要用 X c = a + b; 來測會比較好一點。 讓 compiler 比較容易直接拿 a + b 的結果來建構 c,達到 RVO 的效果,省了中間建構暫時物件的手續。 若用 X c; 然後再 c = a + b; 的話,因為 c 物件已經事先建立起來, 再 c = a + b; 語意上得要另行呼叫 c 物件的 copy assignment operator, 這種操作和 RVO 所要簡省的建構物件的操作是不同類的,因此 compiler 就比較不可能為它最佳化。 : } [...] : 所以主要比較的還是 X1 和 X2 之間的差距,VC 的結果是 X2 明顯優勢, : BCC是 X1 優勢,g++ 是差不多,X2 稍好。也就是說 VC6 的 RVO 技術可 : 能做得不是挺好才會這樣(因為即使 Release 版也是 X2 明顯優勢) : 又,感覺 BCB 的 RVO 是最厲害的,對暫時物件的優化處理向來是 Borland : 的專長。 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 220.130.208.168 ※ 編輯: khoguan 來自: 220.130.208.168 (08/24 10:28)
khoguan:不好意思,我是不是修掉了人家的推文?220.130.208.168 08/24
cppOrz:我的不見了啦~~ 59.120.214.120 08/24
cppOrz:還是可以做 RVO,主要是因為我要讓 X1, X2, Y 的 59.120.214.120 08/24
cppOrz:測試條件一樣,又懶得幫 Y 加 copy ctor 59.120.214.120 08/24
※ 編輯: khoguan 來自: 220.130.208.168 (08/24 11:38)
freaky:VC7.1 和 VC8 debug 版本 2766(X1) vs 2578(X2) 203.70.36.38 08/24
freaky:release版本 0(X1) vs 234(X2) 203.70.36.38 08/24
> -------------------------------------------------------------------------- < 作者: khoguan (Khoguan Phuann) 看板: C_and_CPP 標題: Re: [心得] oprator+ 兩種版本效能測試報告 時間: Wed Aug 24 12:15:59 2005 ※ 引述《khoguan (Khoguan Phuann)》之銘言: : ※ 引述《cppOrz (cppOrz)》之銘言: : : 為了驗證 operator+ 的實作效能,特別寫了幾段小程式測試 : [...] : : X const operator+(X const &lhs, X const &rhs) // 版本 X1 : : { : : return X(lhs) += rhs; : : } : : X const operator+(X const &lhs, X const &rhs) // 版本 X2 : : { : : X t; : : for (int i=0; i<1000; ++i) { t.val[i] = lhs.val[i] + rhs.val[i]; } : : return t; : : } : : void Test1() // 測試程式,做 20 萬次加法運算 : : { : : for (int i=0; i<200000; ++i) { X a, b, c; c = a+b; } : : } : 要測 RVO 的話,可能要用 X c = a + b; 來測會比較好一點。 : 讓 compiler 比較容易直接拿 a + b 的結果來建構 c,達到 : RVO 的效果,省了中間建構暫時物件的手續。 : 若用 X c; 然後再 c = a + b; 的話,因為 c 物件已經事先建立起來, : 再 c = a + b; 語意上得要另行呼叫 c 物件的 copy assignment operator, : 這種操作和 RVO 所要簡省的建構物件的操作是不同類的,因此 : compiler 就比較不可能為它最佳化。 關於我上述論點,剛才我找到 Lippman 的文章,支持我的想法。 請參考: http://www.awprofessional.com/articles/article.asp?p=25033&seqNum=3http://www.awprofessional.com/articles/article.asp?p=25033&seqNum=4 他最後並根據同樣的理路,列出了兩種寫法: 第一種: Matrix mat; while ( something.more() ) { mat = something.fetch_mat(); // do something with mat ... } 第二種: while ( something.more() ) { Matrix mat = something.fetch_mat(); // do something with mat ... } 並說第二種其實比較有效率。這兩種寫法,我之前也想到過, 但就是無法判斷到底哪一種比較好 :-) -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 220.130.208.168