出參一定要是指針?
群里之前有同學問過這個問題。
當時的規范中,強制了這一條,因為彼時的規范該條目主要來自Google C++ Style Guide其中一個歷史版本,比較舊了,當時google還未更新此項。
這個條目是影響面比較大的爭議項。有不少人反饋,之前我寫了個issue(https://git.code.oa.com/standards/cpp/issues/71 )提議修改。
經過和委員們的思考和互動討論,這個條目已經如提議改進了。
可以看到,現在的規范(https://git.code.oa.com/standards/cpp#51%E6%8E%A8%E8%8D%90%E8%BE%93%E5%85%A5%E5%92%8C%E8%BE%93%E5%87%BA)
中, 這個條目已不再強制。
對我們的影響(僅有積極影響)是:存量代碼中這一條目對應的CodeCC告警(Is this a non-const reference? If so, make const or use a pointer)不用改。
該記錄歸檔于此,以后編程可以注意一下。
issue引文:
這個強制條目可能需要改進一下
圖中這項是一個影響非常大的爭議項,問題在于強制。
:) 可能條目比較多,大家沒太注意這項。
這個條目的邏輯稍微有點牽強,說了不少引用的優點,但是轉而說不讓用引用,理由是為了可讀性。
再論可讀性
這個條目成立基于這樣一個前提:“相比引用,指針具有更高可讀性”。
但是,這個斷言并不成立。
所謂優勢
猜想到的,可能體現可讀性優勢的,是這種場景:
callee:
void copy1(const std::string& a, std::string* b);
void copy2(const std::string& a, std::string& b);
caller:
copy1(foo, &bar);
copy2(foo, bar);
然而,不少情況調用處是指針變量,不是一個變量實例前加&求址,這個所謂的優勢蕩然無存。
caller:
ptr_bar = &bar;
copy1(foo, ptr_bar); // 直接傳指針變量
輸入的已經用const修飾了,沒用const修飾的引用很顯然就是輸出參數,指針并沒有比引用更顯式地表達輸出。如此,指針作為出參并沒有可讀性優勢。
即使退一步,假設這樣的寫法是存在優勢的,這樣的場景也有很大的局限性。
因為會直接'&'這樣寫的,只是caller,更確切地說,是初始caller,所以,在一個調用鏈中,只有在最初的caller中才能體現這個假設的優勢。
語義需要明確,而不是基于隱喻
怎么表達一個參數,是類型系統;用一個參數具體做什么,是具體的邏輯,這是獨立的兩件事,一件事不該隱喻另一件事。
可能可讀性最好不要通過取址符這一層隱喻來實現。若論可讀性,自然語言的可讀性最佳,它可以表現在:
- IN/OUT這樣的自然語言增強修飾。(windows以前的用法。我們可能不用宏,更不會用這么短的宏)。
- 顯式的關鍵字。(比如RUST的mut,表示mutable,C#的out,表示output)
- 變量名。(這里對應形參的取名,直接self-documenting為出參)
- 注釋。(如果3仍未滿足)
畢竟,最終caller還是必然得看callee原型的。:) 應該不會有caller不看原型,直接因為有個&,就認為是輸出了吧。
引用比指針具有更高的可讀性
我們的程序有兩種reference,一種是const的,一種不是。
引用的語義比指針更加明確,在這種非此即彼的場景中更是如此。
Modern C++中開發者更愿意把pointer看做nullable reference,而不是把reference看成const-initialized pointer。
引用的本質是常量指針,用意就是作為變量的別名。這樣用目標變量別名即為出參,語義上也更自然。
返回值的本質
函數返回值的本質訴求在于:有一個容器,能容納需要的輸出信息,caller可以access這個容器。
當你選用函數出參實現函數返回值時,這也便成了函數出參的訴求。
如果你使用指針,它將是一個不確定的值,具有不明確的語義。
如果我不希望它為null,那么我為什么總是需要假定它為null呢?這給開發者非常高的心智負擔。
若旨在可讀性,那么,應該直接用Modern C++的返回方式。
強制的影響大
可行性上,眾多項目底層接口(包括基礎庫的接口)本就是用引用的,如果強制不能用,這些功能是必然實現不了的。
成本上,即使可行,修改成本也過高了。這是未來成本。
如果強制,可能經過大幅度修改滿足規范了,但是未來的一天,修改了此項。如果要通過檢查,可能又得改回來。這是潛在的沉沒成本。
綜上,未來成本、潛在的沉沒成本很高。規范中這一條目改進之后,這些成本可以減少。
該條目的提出者,也已經改正了此條目
google minds think alike,谷歌已經改正了這一項。
具體commit:
https://github.com/google/styleguide/commit/7a7a2f510efe7d7fc5ea8fbed549ddb31fac8f3e
https://google.github.io/styleguide/cppguide.html#Inputs_and_Outputs