4 來自Google的奇技 Google-Specific Magic
Google用了很多自己的實現技巧/工具使 C++代碼更加健壯, 我們使用C++的方式可能和你在其他地方見到的有所不同;
[Removed]
4.1 智能指針
Tip 如果確實需要使用智能指針的話, scoped_ptr完全可以勝任; 你應該只在非常特定的情況下使用 std::tr1::shared_ptr, 例如STL容器中的對象; 任何情況下都不要使用 auto_ptr;
"智能"指針看上去是指針, 其實是附加了語義的對象; 以 scoped_ptr爲例; scoped_ptr被銷燬時, 它會刪除所指向的對象; shared_ptr也是如此; 並且 shared_ptr實現了 引用計數, 所以最好一個 shared_ptr對象析構時, 如果檢測到引用次數爲0, 就會銷燬所指向的對象;
一般來說, 我們傾向於設計對象隸屬明確的代碼, 最明確的對象隸屬是根本不使用指針, 直接將對象作爲一個作用域或局部變量使用; 另一種極端做法是, 引用計數指針不屬於任何對象; 這種方法的問題是容易導致循環引用, 或者導致某個對象無法刪除的詭異狀態, 而且在每一次拷貝或賦值時連原子操作都會很慢;
雖然不推薦使用引用計數指針,但有些時候它們的確是最簡單有效的解決方案;
(譯註 看來Google所謂的不同之處, 在於儘量避免使用智能指針, 使用時也儘量局部化, 並且安全第一);
<<<
[Add]
所有權和智能指針 Ownership and Smart Pointers
建議給動態分配的對象一個單獨的固定的擁有者; 使用smart ptr來轉移所有權;
定義:
"所有權"是一個記錄技術bookkeeping technique, 用來管理動態創建的內存(和其他資源); 動態創建的對象的所有者是一個對象或一個函數, 負責保證對象在被刪除的時候不再被使用; 所有權有時可以被共享, 這種情況下, 最後一個所有者負責刪除它; 即便所有權沒有被共享, 它也可以從一段代碼轉移到另一段;
"Smart" pointer 是用起來像指針一個的類, e.g. 重載overload了 * 和 -> 操作符; 一些smart ptr類型可以用來將所有權記錄自動化automate ownership bookkeeping, 確保這些責任和所有者對應;
std::unique_ptr (http://en.cppreference.com/w/cpp/memory/unique_ptr) 是一個smart ptr類型, 在c++11中引入, 表示對於動態創建的對象的專門的所有權; 當std::unique_ptr離開生命週期的時候, 對象會被刪除; 它不能被copy, 但是可以用move來將所有權轉移;
std::shared_ptr http://en.cppreference.com/w/cpp/memory/shared_ptr 是一個smart ptr類型, 表示對於動態創建的對象的共享所有權; std::shared_ptr可以被copy, 對象的所有權可以在各份copy之間共享, 當最後一個std::shared_ptr被銷燬的時候對象會被刪除;
優點:
- 如果沒有所有權邏輯的話, 無形中是不可能管理好動態分配的內存的;
- 轉移對象的所有權比copy對象來得更輕便(如果可以copy的話);
- 轉移對象的所有權比"borrowing"一個指針或引用更簡單, 因爲這樣減少了在兩個用戶之間協調對象生存期的需求;
- Smart ptr可以讓所有權邏輯清晰, 增加可讀性, 自我文檔式, 減少混淆;
- Smart ptr去除了人工的所有權記錄, 簡化了代碼, 排除錯誤error的大型類;
- 對於const對象, 比起深拷貝來說, 共享所有權可以更簡單而有效;
缺點:
- 所有權必須由指針(smart或plain)來代表和轉移; 指針的語義比值語義更復雜, 特別在API中, 你不得不在各種問題中考慮所有權, 別名, 生存期以及易變性mutability;
- 對值語義的性能消耗常常被高估了, 因此所有權轉移帶來的性能補助可能不及在可讀性和複雜性上的損失;
- 轉移所有權的APIs強制它們的客戶使用一個單獨的內存管理模型;
- 使用smart ptr的代碼對於資源release的具體發生地點不明確;
- std::unique_ptr使用c++11的move語義表達所有權轉移, 這是相對較新的特性, 可能讓一些程序員感到困惑;
- 共享所有權容易誘使人們不再進行仔細的所有權設計, 從而使得系統設計變得混亂;
- 共享所有權需要在運行時進行顯式地進行記錄, 消耗比較昂貴;
- 在一些情況下(e.g. 循環引用cyclic references), 擁有共享所有權的對象可能永遠的都不會被刪除;
- Smart ptr並不是普通plain指針的完美替代;
結論:
如果必須進行動態分配, 建議將所有權保留在負責分配內存的代碼部分; 如果另一塊代碼想要獲取這個對象, 考慮傳遞一個copy, 或者傳遞一個指針或引用但不要傳遞所有權; 建議使用 std::unique_ptr來明確所有權傳遞; e.g.
1
2
|
std::unique_ptr<Foo>
FooFactory(); void FooConsumer(std::unique_ptr<Foo>
ptr); |
沒有很好的理由的話, 不要將代碼設計成共享所有權的; 一個原因是爲了避免昂貴的copy操作; 要使用共享所有權條件是: 重大的性能獲益, 操作對象是不可變的immutable(i.e. std::shared_ptr<const Foo>); 如果使用了共享所有權, 建議使用 std::shared_ptr;
不要在新代碼中使用 scoped_ptr, 除非你想要和舊版本的C++保持兼容; 永遠不要使用 std::auto_ptr, 用 std::unique_ptr代替它; [http://stackoverflow.com/questions/13481579/unique-ptr-vs-auto-ptr ]
<<<
4.2 cpplint
Tip 使用 cpplint.py檢查風格錯誤;
cpplint.py是一個用來分析源文件, 能檢查出多種風格錯誤的工具; 它並不完美, 甚至會漏報和誤報, 但它仍然是一個非常有用的工具; 用行註釋 // NOLINT(行尾) // NOLINTNEXTLINE(前一行)可以忽略誤報;
某些項目會指導你如何使用他們的項目工具運行 cpplint.py; 如果你參與的項目沒有提供, 可以單獨下載 http://google-styleguide.googlecode.com/svn/trunk/cpplint/cpplint.py
---TBC---YCR