Avoid Pointer Parameters and Inheritance
Posted on May 22nd, 2007 at 23:16 by fr3@K

Preamble

Microsoft 的 MFC 是最早被大量採用 (massive adoption) 的 C++ library 之一. 等到我開始接觸 C++ Standard Library 這東西都已經是玩了兩年 MFC 以後的事. 還記得, 從一開始對 MFC 的讚嘆與擁抱, 幾年後對它的不屑, 到更後來的理解 (理解不好其實也是有原因的).

即便不少 programmer 知道 MFC 是一套瑕疵遍佈的 library, 可能也知道那些地方有問題. 但它以及部份其他 library 聯手對於更多 C++ programmer 造成的傷害已經留下不容易抹滅的痕跡. 它讓許多 programmer 以為這些東西本來就該這樣 (that’s the way things supposed to be), 當有一天這些被誤導的 programmer 有機會可以選擇另一套 library 或是自行設計的時候, 很容易就陷入 MFC 帶給他們已先入為主的錯誤觀念.


Avoid Passing Pointers as Parameters When You Can

在需要被使用者傳入 struct/class 時, MFC 的 function 在 parameter 上大都 (全都?) 選擇接受 pointer 而非 reference. 它幾乎完全忽略決定一個 function parameter 要被定義為 pointer 或 reference 最重要的一點 - 傳入 NULL 的有效語意. 最簡單決定的法則是如果傳入 NULL 會導致 undefined behavior 或不恰當的結果 (如 assertion failure) 那麼就接受 reference. 這會帶來兩個明顯的好處. 首先, 由於 C++ 沒有所謂的 null reference, programmer 都知道 function parameter 為 reference 的語意就是不接受 NULL. 第二, 如果有人 dereference 一個 NULL pointer 當 function parameter 傳遞, 會在執行時期導致程式 crash 在 caller1 (呼叫該 function 的程式). 這比 assertion failure 發生在 callee (被呼叫的 function) 好多了. 畢竟錯誤是 caller 導致.

Try Harder to Avoid Inheritance

我一直懷疑, 許多 C++ thread library 的設計要求 client 以繼承的方式使用, 是因為受到 MFC 的 class CWinThread 以及 Java 的 class Threadinterface Runnable 影響. 例如這些 thread class:

想像一下以下這個簡單的狀況. 要被平行處理的 algorithm 早被寫成一個 function 準備好被使用. 但為了使用上述這些 thread class, 使用者必須另外寫個 class 來繼承 thread class 並與 algorithm 一起打成一包使用. 糟糕的是, 繼承可說是 C++ 提供的 language features 裡面能對 code 增加最大相依性的單一功能2. 相對的, Boost.Thread 就只單純的抽象了一種能夠被平行執行, 叫做 thread 的單元. 當被執行的 algorithm 不需要 user input (parameter) 時, 只需要把該 algorithm 當作 parameter 餵給 class boost::thread 的 constructor. 在 algorithm 需要 user input 時, 可以搭配 Boost.Bind 使用, 就地產生將 algorithm 與 user input 綁在一起被執行的 functor. 讓程式不但更簡潔優雅, 也讓相依性降到極低.

如果你是個 library writer, 要是你的 class 能以 component class 的方式呈現, 請避免以 base class 的方式實現. 如果你是位 application writer, 使用 component-based library 常常也會是比 framework-based library 更好的選擇.

  1. Crash 在正確的地方也是一種好處 []
  2. 假設你是一個 library A 的作者, 你所寫的一個 class A 繼承自 library B 的 class B. 對你的使用者來說, 他不但直接依賴你的 class A, 更直接依賴來自另一個 library 的 class B. 比方 user 必須能 include 到 class B 的 header. 任何關於 class B 的變動, 你的 user 一併受到影響, 而且被影響的程度可能不比你少多少. []
del.icio.us:Avoid Pointer Parameters and Inheritance digg:Avoid Pointer Parameters and Inheritance spurl:Avoid Pointer Parameters and Inheritance newsvine:Avoid Pointer Parameters and Inheritance furl:Avoid Pointer Parameters and Inheritance Y!:Avoid Pointer Parameters and Inheritance 黑米共享書籤:Avoid Pointer Parameters and Inheritance 推推王:Avoid Pointer Parameters and Inheritance
Previous Post
« Happy Birthday, My Dearest Brother «
Next Post
» 給留言朋友的 Mini HTML 教學與建議 »

27 Comments »

Comment #2909

對對對~~~
我對於類MFC 中所提供的 thread class 也有這樣的感覺
我有自己寫一個 thread template class 後來發現我的想法與 boost.thread 中的類似。只不過boost漂亮多了,我的threas 還要自己寫一個 function object 然後於建立thread 時帶入這個object,這function object 就是我的thread 要去呼叫的他來做些該做的事。我還分兩種1.單次的 2.loop的。
loop thread 就像下面這樣—
== .h file ==
blr::thread::thread_handle m_thread_handle;

== .cpp ==
class get_data_opr : blr::thread::func_obj{
….
void operator () (HANDLE exit_event){…做些摸魚打混的事…}
….
}

//在某 xxDlg::OnInitDialog()
blr::thread::loop_tthread thread;
m_thread_handle = thread(get_data_opr(this), 50, 0);
//在某 xxDlg::OnClose()
m_thread_handle.end();

這樣不需要有一個 member 去參考或指到一個 operator function,因為 class get_data_opr 有 get_data_opr& operator = (get_data_opr& o);

Comment by 烤布雷 — May 24, 2007 @ 0:32


Comment #2910

看到 boost.thread 後…. 我可能就改用它的了,本來還想改善的說。

奇怪應該是這樣的
blr::thread::loop_tthread thread;
怎麼貼上去就變這樣了
blr::thread::loop_tthread thread;

Comment by 烤布雷 — May 24, 2007 @ 0:38


Comment #2911

ㄟ~~~ 這個 template 的”" 都不見了
再試試
“blr::thread::loop_tthread thread;”

Comment by 烤布雷 — May 24, 2007 @ 0:40


Comment #2912

blr::thread::loop_tthread[get_data_opr] thread;
用[ 與 ] 代替一下 template 的 “小於” “大於” 那兩個符號,
實在不知道那”小於” “大於”的符號實際的名稱所以用這兩個好笑的名字稱呼之

Comment by 烤布雷 — May 24, 2007 @ 0:46


Comment #2913

blr::thread::loop_tthread[get_data_opr] thread;
用[ 與 ] 代替一下 template 的 小於 大於 那兩個符號,
實在不知道那 小於 大於 的符號實際的名稱所以用這兩個好笑的名字稱呼之

Comment by 烤布雷 — May 24, 2007 @ 0:49


Comment #2914

因為 <xyz> 會被認為是個 html 的標籤, 通常是被忽略的無用標籤.

要寫成這樣:

  • <pre><code><xyz></code></pre>

或是這樣:

  • &lt;xyz&gt;

才會如你所要的顯示. 通常我會用第一個方法把我寫的 code 整個包住. 這樣連內縮 (indentation) 也會一併被正確顯示.

我沒看懂你的 code, 重寫一次吧. 之後我再幫你把上面那些刪掉.

另外, 註冊一個帳號, 就可以修改用該帳號寫的留言喔. 就不用我幫你修改/刪除了.

Comment by fr3@K — May 24, 2007 @ 1:28


Comment #2940

Avoid Passing Pointers as Parameters When You Can

可以對這點稍做說明嗎? 是指多使用 Reference, Templete 還是指像 Bind 的Function Composiition 嗎?Pointer 和 Reference 據我所知功能都一樣,Pointer 比較 Generic

Try Harder to Avoid Inheritance

Function Composiition 會造成 Close coupling 這點和 Javascript 很像,但的確比較適和 Event driven, 所以支持!

Function Composition 也被很多人研究過
在 Perl 是叫 Anonymous function closure

關於 Function Closure http://en.wikipedia.org/wiki/Closure_%28computer_science%29
關於 Function Composition Limitation 和 Attempt to Function Closure in PHP
http://devzone.zend.com/node/view/id/2013#Heading1

Comment by *** — May 27, 2007 @ 4:58


Comment #2943

關於第二點的 OOP 問題再補充一點,用 Inheritance 的確像是不妥當。在 Java 是使用 Interface 比較多,但據我所知 Inheritance in C++ supports multiple inheritance 所以 Inheritance 可能已經是在 C++ 世界中最好的方法。Since thread subclass allows the factory pattern to be used for easy polymorphism on creation and deletion threads. Thread safe, lock 問題也比較容易 get inspected before actual running time, 所以在 3 以上的線程應比較容易使用?原因是因為比起像 Function Composition 放在同一個 Object 內,可建立數個 Objects 來分開計算和隔離

在 algorithm 需要 user input 時, 可以搭配 Boost.Bind 使用, 就地產生將 algorithm 與 user input 綁在一起被執行的 functor. 讓程式不但更簡潔優雅, 也讓相依性降到極低.

對於沒有 Inheritance 的 Function Composition 比較像是另一個世界,這得確是 Asychronous event driven programming 最佳寫法也是 framework 想辨法簡化的東西

Function Composition 的好處就如上所說。改良後就變成 Javascript 的 Runtime OOP + Function Composition + object reflection 的世界了

Comment by *** — May 27, 2007 @ 5:39


Comment #2951

***,

我指的是 pass-by-reference vs. pass-by-pointer. 對 C++ 來說, reference 與 pointer 的差異在於兩點:

  • Pointer 可指向 NULL, 而 reference 必須指向 instance
  • Pointer 可以改變指向的對象 (T* const 除外) 而 reference 不能, i.e. reference 的整個生命週期都指向同一個 instance

從上面兩點可以看出跟 reference 比起來, pointer 的確比較 generic, 能用在更多地方, 可以用 reference 的地方以 pointer 代替應該都沒問題.

問題就是出在它比較 generic, 請參考 section `Macro Side-Effect, C++ Specific’ in C/C++ Tips - The Marco Assert. 相對的 reference 限制較多, 是個拿來定義 precondition 與 postcondition 的好工具.

Avoid inheritance 與 closure 無關. 如你已經知道的, C++ 已經有以 library (Boost.Lambda 與這篇提到的 Boost.Bind 以及 STL 的 Bind 等等) 的形式支援 closure (other than function local classes), 請參考 (How do you) lower (or upper) your strings, the STL way 的 copy_lower_boost 這個 function template. Lambda/bind 在這篇的例子中也只是可以用來避免 inheritance 的手段 (當然也能用在許多其他時候).

你真的中了 OOP 的毒太深了. Think in C++, don’t think in OOP!

Comment by fr3@K — May 27, 2007 @ 12:17


Comment #2952

***,

I tried to write an article about “OOP - To Be Or Not To Be” (but failed to finish it). In Java world, programmers are forced to do OOP, every method is virtual method and having base class as java.lang.Object, but price is paid as Memory and Performance cannot compare to more controllable OO Languages, C++ and D.

Having experienced with both C++ and Java (and lot of others), it really tells me that classes library should not have excessive usage of OO inheritance and virtual methods, as it’s COSTS, which means if C++ class library is designed EXACTLY like Java classes then you would expect its performance and memory consumption are probably slightly better then Java but no where near better than the BEST designed C++ class libraries with careful consideration of OOP’s cost.

Anyway, my personal consideration are it’s like trade offs in between, if simply straightforward OOP is more important as its productivity then stick with it, and if you see the performance and memory usage as top priority then you might take second consideration when design your classes library, a good example of this is MS WTL.

Comment by Nash — May 27, 2007 @ 16:44


Comment #2953

***,

Don’t get us wrong. You seem to know quite a few things, which is really impressive for a junior (provided my guess was correct).

If you keep your mind open, you maybe just a few steps away from entering the next level. Believe me, people commented in this thread (me, 烤布雷 and Nash) had been where you are at now, except we came through. I sincerely hope you could, too.

OOP is one of the paradigms C++ provides, and yet C++ gave us quite a few more. That’s why many love C++ and are sticking with C++. There is nothing wrong with OOP, but it’s certainly not the best way to solve ALL programming problems.

From your IP logged on my server, it appears you are visiting from the east side of Canada. I express myself better in English, sometimes, hope you won’t mind.

Cheers~~

Comment by fr3@K — May 27, 2007 @ 21:11


Comment #2957

Thanks for your considerable advices, and in fact they had helped a lot without your knowing. You were right about me, and about everything, which had surprised me a lot too, considering I don’t usually leave comments on blogs or forums.

First of all, I hope I wasn’t doing anything that ruins your professional blog. If it did, my apologies and I will stop it from happen again in the future. Please don’t worry about my feeling. Feel free to lambaste me to the bottom of the hell :) I will be reading the books you recommend to me

I had a feeling that my comments weren’t straight to the point your were trying to express. Next time I will be straight to the point of discussion, that is, if you don’t mind. All my techniques are basicly from my personal reading while in school. They are only theories based on the theoretical environments so I don’t know if they are useful, practical or orthodox. I need help. :(

Back to the pointer/reference question,
I understand all the basics such as points, references, etc. in school. and from my knowledge I know C++ doesn’t have a base class (ie. like the Object class in Java). Isn’t a referece will severe cripple the ability for generic programming? without generic programming for MFC, MFC couldn’t be possible for VB6 to use anymore, or the old C lib to coexist with C++. I understand that in real world C is more portable than C++. If only a slight assert to be added can bring more portability, I will.

And because References are typed but Pointers are not, MFC would otherwise being forced to create a base class to be built upon if reference design is used instead. and the non-OOP side of C++ like char array or simple struct would be cease to function with Reference due to no heritage relationship to the base class?

Furthermore generic pointers can replace any refereces, except the null issue you addressed. Reference is good for pure C++ in design if following issues are not a problem.
1. no base class.
2. rvalue reference may become a stanard, then assert NULL need to be used again.

for point 2, the rvalue reference in C++ idea had already been possible with other C++ alike language like PHP, or Pascal a long time ago.

or were your referring a reference pointer? I would love to use a reference pointer but C++ has reference, pointers and reference point. that means it only covers 1/3 of population.

C++ favors defensive design not design by contract, therefore more freedom should be allowed. Error detection is only by choice. shouldn’t count on the assertion. develoeprs should treat itlike they were no assertion at all and read API document carefully.

defensive design: http://en.wikipedia.org/wiki/Defensive_programming
design by contract: http://en.wikipedia.org/wiki/Design_by_contract

Comment by *** — May 28, 2007 @ 9:09


Comment #2958

quote from defensive design

# Assertions

* Within functions, you may want to check that you are not referencing something that is not valid (i.e., null) and that array lengths are valid before referencing elements, especially on all temporary/local instantiations. A good heuristic is to not trust the libraries you did not write either. So any time you call them, check what you get back from them. It often helps to create a small library of “asserting” and “checking” functions to do this along with a logger so you can trace your path and reduce the need for extensive debugging cycles in the first place. With the advent of logging libraries and Aspect Oriented Programming, many of the tedious aspects of defensive programming are mitigated.

Comment by *** — May 28, 2007 @ 9:38


Comment #2959

Avoid inheritance 與 closure 無關. 如你已經知道的, C++ 已經有以 library (Boost.Lambda 與這篇提到的 Boost.Bind 以及 STL 的 Bind 等等) 的形式支援 closure (other than function local classes), 請參考 (How do you) lower (or upper) your strings, the STL way 的 copy_lower_boost 這個 function template. Lambda/bind 在這篇的例子中也只是可以用來避免 inheritance 的手段 (當然也能用在許多其他時候).

你真的中了 OOP 的毒太深了. Think in C++, don’t think in OOP!

我也覺得了解不用 Inheritance 的寫法也是值得的, 請原諒我之前的說法,您的文章充滿了我以前前所未見的技術,令另我很興奮。我絕對不是反彈,我也很想試試您所說的方法

那時我想說的不是反對不用 Inheritance 而是想問。Bind 就好像 C 的 Function pointer 的 OO 版本,所以自然也是 OO 的功能,只是覺得為什麼 OO 的 inheritance 反而幫不上忙?現在我也了解您的意思了,你是說 3rd party thread class 常常會被修改,所以 dependecies 會有很多問題

MFC 的 ThreadClass 就只像一個 Stunt.. 一個 Interface 又或 Abstruction
原因是 MFC ThreadClass 都不會變的,最多也只有 Bug fix,會變的 3rd party class 那種就如你所說的, Less dependency the better. Java 從 1.0~1.5 Official Thread class 也沒有變過。所以我想說的是大家都知道不會變所以使用 Inheritance。如果要使用 3rd party thread lib 就要如您所說的,Remove the dependencies

Comment by *** — May 28, 2007 @ 10:53


Comment #2960

更正確的來說, 我的意思是, inheritance 所引進的 dependency 很高, 我認為應該要能避免就避免 (避免非必要 dependency). 這原則並不是只對那些 thread classes 適用, 只不過它們剛好被我拿來當作反面教材.

=============================================

from my knowledge I know C++ doesn’t have a base class (ie. like the Object class in Java). Isn’t a referece will severe cripple the ability for generic programming?

在 C++ 的世界, OOP 與 GP (generic programming) 是兩個平行的 programming paradigm. 它們可以一起被使用, but that’s only when programmers choose to, i.e. neither depends on the other. 沒有你說的因為沒有 common base classes 可能 cripple generic programming 的問題. 譬如說可以只用 function 與 built-in types 來 GP. 這點 Java 好像不太一樣?

=============================================

without generic programming for MFC, MFC couldn’t be possible for VB6 to use anymore, or the old C lib to coexist with C++.

我想你說的應該是 .Net 或是 COM, 而不是 MFC. MFC 不能被 VB 使用. But again, it has nothing to do with GP, C++’s GP sub-system is just too complicated to be reflected in other programming languages. 我猜你有點把 OOP/C++/Java 搞混了. Old C lib 與 C++ 的共用性也跟 GP 無關, 基本上, 透過一些技巧 (extern “C”, wrapper and etc.), C 與 C++ 之間都是可以互通的.

以 COM 來說 (.Net 我知道的很有限, COM 稍微好一點), 它為了跨語言 (amoung microsoft programming languages), 的確用了 common base class, i.e. interface IUnknown, interface IDispatch and etc. 畢竟這些東西我不熟, 所以我還是不評論以免誤導了你, 只提供你另一種作法當作參考. (至少 open source 的) 我所知道的 scripting language 都提供 C binding, 也就是說能與 C 互通. 以 PHP 來說, 它提供了 API 給 programmer, 讓 programmer 可以寫出能被 PHP 呼叫的 function (PHP extensions). 前面說過了, 基本上能與 C 互通就是能與 C++ 互通. 所以比較大的問題應該是在於其他 language 與 C 互通的介面沒有統一, 而不是能不能互通的問題. 但解決這問題的方法絕對不是只有 COM 才行, 只要能統一介面就成功一大半.

=============================================

References are typed but Pointers are not

錯, pointer 與 reference 一樣, 也是 typed. 除了 void* 之外.

=============================================

MFC would otherwise being forced to create a base class to …

除了已經被討論到的差異之外. 如果 reference 有其他缺點 pointer 也都有. In terms of implementation, they are essentially THE SAME things. 你對它們的同與異有誤解, revisit your favorite C++ text book for detail. If you don’t have one, I recommend The C++ Programming Language.

=============================================

rvalue reference may become a stanard, then assert NULL need to be used again.

Maybe.

    
    string str_a(std::move(str_b)); // line 1
    cout < < str_b; // line 2
    

別忘了 C++0x draft 的規範是, 在被 move 之後, str_b 還是得處於一個有效的狀態 (valid state), 依然可以被參考. 也就是說 line 2 不用去檢查 str_b 是否語意上為 NULL. 只是內容可能為 `空’.

=============================================

I would love to use a reference pointer but C++ has reference, pointers and reference point. that means it only covers 1/3 of population.

I have no idea what you are talking about.

=============================================

C++ favors defensive design not design by contract, therefore more freedom should be allowed. Error detection is only by choice. shouldn’t count on the assertion. develoeprs should treat itlike they were no assertion at all and read API document carefully.

I haven’t given this point much thought, it could be true, in general.
Pass-by-reference is actually design-by-contract, a.k.a. Don’t give me NULL!!!

Comment by fr3@K — May 28, 2007 @ 14:05


Comment #2961

I don’t like to argue but just to clarify a few things.

我想你說的應該是 .Net 或是 COM, 而不是 MFC. MFC 不能被 VB 使用. But again, it has nothing to do with GP, C++’s GP sub-system is just too complicated to be reflected in other programming languages. 我猜你有點把 OOP/C++/Java 搞混了. Old C lib 與 C++ 的共用性也跟 GP 無關, 基本上, 透過一些技巧 (extern “C”, wrapper and etc.), C 與 C++ 之間都是可以互通的.

Umm, VB has MFC. becasue MFC means Microsooft Fundamental Class. The last character C doesn’t stand for C language. Basicly you code the same in VB with MFC API which is based on C++ lib, and of course, the lib was compiled with C++ compiler. In other words, you code VB like C++ , use C++ structures, use VB primitive type to emulate C++ primitive types but in VB language. all object, method calls are the same. I like this idea as MSDN covers both API usage in 1 common C++ API.

Therefore it has to be generic. VB has a different class structure than C++ does. (with different primitive types) Only void* type allows generic for them to talk. If you are you going to try it. soon you will realize VB does have base class but C++ doesn’t. Referencing just not going to work without changing C++ language. (However Referece pointers will work. I dont know the real name of the term. Is it called Pointer reference? but I will address this below by real codes so you can understand my idea.)

透過一些技巧 (extern “C”, wrapper and etc.), C 與 C++ 之間都是可以互通的.

The same way you use it in Delphi, VB language to import lib from C/C++ directly or from the .dll, etc. this a bit off topic. I am glad you mentioned this.

錯, pointer 與 reference 一樣, 也是 typed. 除了 void* 之外.

Yes, I do understand this. Its my bad that I didn’t say generic pointer on the first place. void* was what I referred to. becasue MFC uses void* like Win32 API did for generic support on all most computers languages. VB, Pascal, Effiel, … around that time being developed.

Those generic lib has their reason to exist on earth, without them there is no generic connection to help C/C++ to be used in other languages without COM.

COM is made by MS for multi-process purpose. basicly the RPC. Its way more powerful than just combine 2 different language together.
Now .Net, as you know, more powerful than RPC in general, it has an application server with virtual machine structure. MS did give C# a common base for a start.

Even before .com days languages were uniformed by linker. The common type is crucial for them to work, and the candidate types were C primitive types, including the pointers. Being generic is what MFC has tried to accomplish. I don’t know about the creation idea of other packages, or their philosophies but I do know that MFC favors generic types to bring in portability among its featured VB languages, or their C based windows in general.

C++ had some problem of its own, which I thought generic was also the solution.

1. you don’t know the style the programmer would use.
for example. in C++ you can use pointers [ int *a ] for basic function needs
or reference [ int a = &b ] I will describe this method of function calling below.
or reference pointer [Classname *a] (which Java just call them reference instead since everything in java is a reference pointer basicly)

Please keep my term in mind, because I don’t really know which one you referers to. reference assignment or the reference pointer.

Ok now so far I think you will say I had the naming wrong. Reference pointer should be called Reference. I am not sure about this the naming so please correct me, but naming however is irrelavant.

As for referencing
For a function that used reference passing
It looks like this

Integer a;
Integer c;
functionname (&b) {
b =& c;
}

clients never need worry about pointer repositioning, which is for example, after a had been passing functionname, it won’t reference to b after function finish execution. you would only expect value changes not reference changes.

Example would be.

functioname(a);
a never equals to c here. remained unchanged. the function wouldn't change a just by use it as an function call argument. side-effect is zero.

別忘了 C++0x draft 的規範是, 在被 move 之後, str_b 還是得處於一個有效的狀態 (valid state), 依然可以被參考. 也就是說 line 2 不用去檢查 str_b 是否語意上為 NULL. 只是內容可能為 `空’.

as I mentioned on the above example. rvalue is pretty safe. even on temp variables which returned by functions. This trait is actually imported by PHP which PHP doesn’t need referece pointer at all to do anything. I was wondering why it is still a draft in C++. It isn’t new, and its safe. What were they waiting for.

for reference pointer programmers. its basicly allow them to change the variable like they did in the pointer. More power, yet still have strong typed OOP object reference on top of generic pointers. The side effect is like the pointers. Unknown. May hurts the security.

Ok I have described 3 ways for a class object to be created in general. Can they coexist ? Yes. Are they easy in C++ ? Yes easy. Is it Cross-language, Yes, but not for the reference argument passing.
——
The term refererce arguement passing is this…

functionname (ClassA &a, ClassB &b, ClassC &c) {
}

——
if your language doesn’t support OO, it will fail.
Does reference pointer arguement passing work in non-OO language. Yes it does, becasue its still a pointer. just a reference( if my term is different from your, this would be a variable) wrapped by a pointer

That’s why MS did generic instead. It fits their purpose. Their design choice.
I believe many 3rd party lib thought the same, used the same way.
If C++ no longer cares about C users. They will use full OO.

This is off-topic. Delphi is an interesting beast. It has C++ world, Java world, and C++ OO world. The java world has DOM referencing counting interface. auto garbage collection. all the java features are optional in Delphi. Its fast.

除了已經被討論到的差異之外. 如果 reference 有其他缺點 pointer 也都有. In terms of implementation, they are essentially THE SAME things. 你對它們的同與異有誤解, revisit your favorite C++ text book for detail. If you don’t have one, I recommend The C++ Programming Language.

I do believe your reference equals to my own term, the “Reference pointer”. If that’s the case, then I believe your term “Reference” is stronger than Pointer. It gets 1 more wrapper to describe a type. cross-platform, and may be use in all or non OO languages.

Ok I must admit that your term reference confused me. Every language got their “reference” term differently. The java reference may not be the same as C++. its known that PHP and Java are completely different but they all call their variable a reference. so I had used code sample to describe at begining.

I haven’t given this point much thought, it could be true, in general.
Pass-by-reference is actually design-by-contract, a.k.a. Don’t give me NULL!!!

Agreed. design by contract would check preconition. defensive design never validates the inputs pass to a function. ie. generally like a user in front of a computer STDIN some input and never get validated when feeding them to a function.

Comment by *** — May 28, 2007 @ 17:10


Comment #2962

如果 Classname *a; 對你來說是叫 Reference 的話

Functionname (Classname *a, Classname *b) 對你來說是 passing reference 的話那我們其實早就有共識了,只是我不知道你的 Reference 的意思

因為 PHP 的關係, 我想的 Reference 是
Functionname (Classname &a, Classname &b)

在 Java, Pascal, VB Reference 指的是
Functionname (Classname *a, Classname *b)

我不知道為什麼每個語言用不同的名詞..

如果你說的 Reference 是 Java 的 Referece 的話,那麼就如你所說,和 Pointer 一樣,對其它的語言支援也完全沒有問題, 只是麻煩了一點,所以用 void* 是為了給 non-OO 如 C 語言方便

如果你說的 Reference 是像
Functionname (Classname &a, Classname &b)
的話,那 Non OO 的語言一定就不行了….

Comment by *** — May 28, 2007 @ 17:57


Comment #2963

當我提到 reference 時, 除非特別註明, 否則都是 C++ reference, e.g.:

    
    type & reference;
    

================================================

I like this idea as MSDN covers both API usage in 1 common C++ API.

Yes, they do that in .Net reference. See DateTime for example.

我已經好幾年沒碰 Microsoft 的專有技術, 能忘的早就忘了, 還記得的也很久沒更新了. 如果我說錯了, 不要客氣請指正我 :). 是的, 我知道 MFC 的 C 是 class 的簡寫 XD. 我 google 了一小下, 依然找不到 VB 使用 MFC 的說明, 我想還是你搞錯了, MFC 並沒有支援 VB.

================================================

Therefore it has to be generic. VB has a different class structure than C++ does. (with different primitive types) Only void* type allows generic for them to talk.

I don’t know what’s VB’s protocol to C++ under such scenario. AFAIK, MS’s CLR/.Net was built in part to serve that purpose.

Anyhow, I failed to see how VB (or any language) could manipulate a void pointer (void*) accurately . 除非, 用 human protocol, programmer A tells programmer B or have it documented, 或是這個 pointer 的意義就只是拿來傳遞一個 memory address, 那當然可以被做 memcpy() 等比較 low level 操作. Which wouldn’t be the case in general. 想像一下如果 A 要求 B 把一個整數值寫在 P 所指向的 memory address:

    
    void B(void* P)
    {
        // missing type information, can't do this!!!
        *P = MAGIC_NUMBER;
    }
    void A()
    {
        int V;
        B(&V);
    }
    

Pointer to void is not generic, but perhaps convenient sometimes.

================================================

becasue MFC uses void* like Win32 API did for generic support on all most computers languages

Yes, but that’s Win32 SDK (API), which MFC is built upon. But NOT MFC, MFC uses pointer to classes mostly. See CView::OnPrint for example.

讓我就這個例子做點說明. 這個 function 是一個 callback, 它的第一個 parameter 是一個指向 CDC 的 pointer, pDC. 當它被呼叫的時候 pDC 一定不會是 NULL. 這個時候就不該用 pointer 來當參數傳遞.

================================================

我從沒說過 void* 不能解決特定問題. 應該是你誤會我了. 但既然提到了, 我還是要表達一下我的看法. void* 的確能作為某些特定問題的答案, 但它絕對不是通用的好方法, 不應該被鼓勵. void* 的好處是你甚麼都能做, 延續上例, B 的作者可以把 B 寫成:

    
    void B(void* P)
    {
        int* V = reinterpret_cast(P);
        *V = MAGIC_NUMBER;
    }
    

End of the story? Wrong, we can’t use C++’s type system to tell the author of B not to do this instead:

    
    void B(void* P)
    {
        short* V = reinterpret_cast(P);
        *V = MAGIC_NUMBER;
    }
    

================================================

I am just gonna skip the parts where I am scratching my head confusing, ’cause you use non-C++ terms. Partly because I am lazy, partly because I want you to find out what they are called in C++, if they exist in C++, e.g. a part of C++’s language feature.

Keep in mind a reference in C++ is very much like an alias. It has to point to something but NULL when initializing and can’t be changed to point to something else once initialized:

    
    void foo()
    {
        int v1, v2;
        int& r = v1; // ok
        r = v2 // this is equivalent to v1 = v2!!
    }
    

================================================

如果你說的 Reference 是 Java 的 Referece 的話,那麼就如你所說,和 Pointer 一樣,對其它的語言支援也完全沒有問題, 只是麻煩了一點,所以用 void* 是為了給 non-OO 如 C 語言方便

如果你說的 Reference 是像
Functionname (Classname &a, Classname &b)
的話,那 Non OO 的語言一定就不行了….

這篇只談 C++, nothing else.

Comment by fr3@K — May 28, 2007 @ 19:30


Comment #2966

抱歉,的確是我記錯了,VB 自己有一個和 MFC 相像的 VB Runtime Lib
有相通的只有 Borland C++Builder 和 Borland Delphi (沒有使用 DLL),而是用 Linking 的方法,這是題外話…

現在我了解你的 Reference 的意思,所以可以更準確的說明
我以前說過的,就忘了它們吧,也很抱歉我之前可能有誤會你的意思

基本上 Wiki 都說明 Reference 的不足了

because the operations on references are so limited, they are much easier to reason than pointers and are more resistant to errors. While pointers can be made invalid through a variety of mechanisms, ranging from carrying a null value to out-of-bounds arithmetic to illegal casts to producing them from random integers, a reference only becomes invalid in two cases:

* If it refers to an object with automatic allocation which goes out of scope,
* If it refers to an object inside a block of dynamic memory which has been freed.

The first is easy to detect automatically due to static scoping of variables; the second is more difficult to assure, but it is the only concern with references, and one suitably addressed by a reasonable allocation policy.

原因是因為 reference 較 pointer 安全, 能在不影響目前 Code 的前提下我一定會用。已知的如下, 在 rvalue 出來之前會有一些問題
如無法使用 macro 製成的 constant,
每個 constant 要使用前要當 variable 定義, 如 char& a = NULL; 不行,要用
char temp = NULL; char& a = temp; 這如果用在 function calling 上的話也就是說在使用每個 literal 之前都要設成 variable, 不然就要使用 static class member, Macro 產生的 literal (constant) 自然也不能使用

當然如果硬要解決的話,這些都可以解決,不過比起使用 void * explicit cast 恐怕強不了多少。

使用 void* 會有很多麻煩,那些麻煩你都提出了,如太多的 explicit casts,我想大家也都很熟悉那些麻煩接下來會有什麼事發生。

如果使用 Pointer to Class 有 Reference 所有的功能,自由度也較大
這些問題都會消失, 比較不安全但是方便使用? 所以也是 MFC 用 Pointer to class 的理由?

——–
這點 rvalue 的最大功能你可能漏掉了, 我以我加在最後
Foo (char && A);

這有一個 & 做不到的東西就是你可以

Foo(’A');
Foo(NULL); // ps. NULL = 0 literal
Foo(64); // assign ascii

Comment by *** — May 29, 2007 @ 5:30


Comment #2968

我的論點是說

如果在 rvalue 出來之前就用 referece 方法的話,那麼所造成的問題決對比加一行 assert (XX != NULL) 還多

沒有必要為了不要 assert 就要造出更多問題。等 rvalue 出來再說也還不遲

況且 C++ 是 defensive design 用什麼語言想什麼事,再怎麼寫別人也不會不測試就相信你的 Code。Assert 本來就不是 C++ Library 設計者做的事, Library 設計者正常來說連 Assert 都要懶的寫才對

原則來說我歡迎大家寫更安全、方便東西,但我還是會自己寫 Assert 測試它們,因為這是 C++ 的原則, 寫 Code 的人要測試不是寫 Library 的人,寫 Library 的人只要寫好 Documentation 脫離責任就好。反而是 Coder 要注意 Documentation 內寫什麼

Comment by *** — May 29, 2007 @ 7:03


Comment #2970

***,

Glad some of the confusions are cleared. One more thing you still misunderstand (hopefully the last :-)):

這點 rvalue 的最大功能你可能漏掉了, 我以我加在最後
Foo (char && A);

這有一個 & 做不到的東西就是你可以

Foo(’A’);
Foo(NULL); // ps. NULL = 0 literal
Foo(64); // assign ascii

Quoting myself:

我指的是 pass-by-reference vs. pass-by-pointer.

I was talking about pass-by-reference vs. pass-by-pointer, but not pass-by-value nor rvalue-reference.

Comment by fr3@K — May 29, 2007 @ 9:36


Comment #2971

What is pass by reference?. I went to look on wiki you told me to look.

Read it carefully. Fr3@k :)

en.wikipedia.org/wiki/Reference_(C++)

Examples:
1. int A = 5;
2. int A;
3. int& rA = A;
4. extern int& rB;
5. int& foo ();
6. void bar (int& rP);
7. class MyClass { int& m_b; /* … */ };
8. int funcX() { return 42 ; }; int (&xFunc)() = funcX ;

What is pass by reference? They are all pass by reference examples.
Look at #6

rvalue is made to replace #6 by changing

void bar (int& rP);

To

void bar (int&& rP);

To bring up more power to reference passing.
This is not “pass by value” nor “pass by rvalue reference”
Pass by value in C++ means pass by a memory address(pointer value)/ or primitive types.

——
Your quote

I was talking about pass-by-reference vs. pass-by-pointer, but not pass-by-value nor rvalue-reference.

Note I didn’t talk about pass by value nor rvalue-reference. I talk about the limitation of pass by reference.(the #6 above). and explain the similarity of rvalue reference passing which adds more feature to traditional reference passing to overcome the limitation of reference.

If you think I am doing pass by value, then you are wrong. they are the real “references” in C++. you probably mess up the term with the Referece in Java. They are obviously different according to wikipedia

Pass by reference in Java != Pass by reference in C++
Pass by value in Java = Pass by value in C++

Java has different meaning for “reference” keyword. so Please read wikipedia you told me to. C doesn’t have reference, but they have pass by reference. The reference means “pointer” value there. It is basicly >>pass by value< < except work on a pointer value. In C++ they formalize the >>Reference< < terms. so its a different beast.

In C++, pass by reference means pass by >>referencing<<
I assume you talk about C++ right?

Comment by *** — May 29, 2007 @ 10:54


Comment #2972

Read this: http://en.wikipedia.org/wiki/Pass_by_reference#Call_by_reference
And note the quote on page top: for example, C++ combines call-by-value with call-by-reference
The call (or pass) by reference term had changed in C++ for their new reference.
C++ is the most confusing language I ever seen. Not to mention different terms used in different C stage (I talk about C and C++ ). Be careful on old books

Comment by *** — May 29, 2007 @ 11:24


Comment #2973

What is pass by reference? They are all pass by reference examples.

Wrong, only #6 is. Others were merely various usages of C++ reference (possibly an incomplete list), but not passing.

============================================

If you think I am doing pass by value, then you are wrong. they are the real “references” in C++. you probably mess up the term with the Referece in Java. They are obviously different according to wikipedia

I am not sure what you wanna “pass-by”, but dude, I wrote about a mistake in C++ Reference Guide (though they have not corrected their content, yet) regarding rvalue-reference and you suspect I might have problem understanding what a C++ refernce/rvalue-reference is, in comparison to some average Joe? Though that post doesn’t really mean anything significant, but it should tell you a few things, I am capable of correcting even THE experts and I know what I am talking about (well, at least mostly).

Yes, I am likely to be wrong about Java stuffs (among others), but rarely in C++. I certainly would not messed it up with another language in this blog, because I don’t write about other languages in this blog (ok, maybe briefly from time to time, but I always disclaim myself as being a reliable source other than pure C++ which I’ve tried to tell you quite a few times).

============================================

In C++, pass by reference means pass by >>referencing< <

Wrong, referencing (the verb) is something else. As in, one could reference an instance via the instance itself (obviously), a pointer or a reference, etc.

C++ combines call-by-value with call-by-reference

Ok, I was wrong, it looks like I was using the wrong terms. I should’ve used “call-by” instead of “pass-by”.

I don’t think you understand your quote from wikipedia. It means C++ supports both call-by-value and call-by-reference.

Though Wikipedia is sometimes not a reliable source (I’ve personally made a few corrections on both the English and Chinese Wikipedia), however, that paragraph you quoted was correct, but you failed to understand what it was trying to say.

Comment by fr3@K — May 29, 2007 @ 14:37


Comment #2975

***,

I want to share with you the same (friendly) advise I told another reader not long ago:

Please be less assertive in wording next time, otherwise I would expect you to know what you are talking about, or at least followed links in my post.

I share this with you not to make you feel bad or anything, but in hope it would benefit you.

Cheers~

Comment by fr3@K — May 29, 2007 @ 15:48


Comment #2976

Your attitude is so aggressive. I don’t know what to say.

Comment by *** — May 29, 2007 @ 18:56


Comment #2977

***,

It’s my intention to be assertive, but not aggressive. As to demonstrate what I felt when I read your comments. I think I was a bit emotional as I look back my reply now, don’t feel offended, it wasn’t meant to be personal. If, however, your perception of my words were offending, I would appologize, at a personal level (but not because I should).

You need to learn the etiquette to communicate with strangers on Internet (blogs, newsgroups, mailing lists and etc.), in order to avoid unpleasant experience. Especially when the person is possibly a reliable source.

When you see things they say which you think are NOT (entirely) correct. First study reference from other reliable sources, then if you are still convinced you were right, write something like the following:

    THIS-PAPER (with link) I read from THIS-AUTHORITY (with link) says it’s FOOBAR instead of BARFOO. Would you care to clearify things up?

or if you can’t find another reliable source, perhaps you could try:

    I can’t remember where I got this from, but I was under the impression that it’s supposed to be BARFOO instead of FOOBAR. Would you elaberate further regarding this subject?

I may have gone to far trying to tell you a few things in life other than C++, which isn’t really my expertise :).

Finally, I consider myself being friendly to you. Perhaps not always in a polite way, but certainly was trying to point you to the direction which I believe was right.

Comment by fr3@K — May 29, 2007 @ 20:45


Comments RSS TrackBack URI

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>