發表文章

目前顯示的是 三月, 2012的文章

Effective C++ item 31: 將檔案間的編譯依存關係降至最低

C++ 相較於 Java, 可以直接在 stack 上配置物件, 而不是全部都是 pointer (reference), 因此, C++ 要求在 include class 時, 得知道該 class 的所有 member field, 才知道要配多大的空間。這帶來一個問題, 即使 header 檔改的是 private member field/method, 全部有引入該 header 的檔案都要重編, 專案變大後, 是頗為痛苦的事。 解決這問題有幾種作法, 基本精神就是架空 class, 讓它不會有更動 private member field/method 的機會。書上提出兩個作法: 使用 handle class, 或稱 pimpl idiom (pimpl: pointer to implementation) 使用 interface class (abstract base class) 以 class Person 為例, 第一個作法是在 Person 裡加上一個 private member: PersonImpl *pImpl, 然後所有方法都透過它執行, 例如:std:string Person::name() const { return pImpl->name(); } interface class 則是全部方法都宣告為 virtual 並不提供實作 (別忘了提供 virtual destructor), 這樣 Person 不能初始化, 效果如同 Java 的 interface (不過有彈性可提供 method 和 field), 像這樣:class Person { public: virtual ~Person(); virtual std::string name() const = 0; ... } 然後再寫個 class RealPerson 繼承 Person, 提供真正的實作。 於是, 不管用 handle class 或 interface class, 只要沒有加減 interface 的 method, 相依 Person 的程式都不需重編, 邏輯上也做到令用戶端程式相依於介面而非實作, 達到良好的封裝效果。當然, 相對於直接實作 class Person, 兩者…

vim 快速開啟 .c / .cpp / .h 的相對檔案

搜尋這個需求的話, 會看到網路上一個廣為流傳的版本: map <f4> :p,.h$,.X123X,:s,.cpp$,.h,:s,.X123X$,.cpp, 開 .cpp 後按 F4 就可以開啟同目錄下的 .h; 反之亦然。只要一行就搞定, 沒有 if-else, 頗為神奇的。 但是有時候我開 .cc 或 .c 時, 就沒辦法叫出 .h 檔, 所以剛才花了點時間研究一下, 才搞懂它怎麼做的。 修改後的版本如下, 這個版本在 .cpp / .c / .cc / .C 檔案裡按 F4 會開 .h; 在 .h 裡開 F4 會開 .cpp: map <F4> :vs %:s#\.cpp$#.XY_CPP_XY#:s#\.h$#.cpp#:s#.XY_CPP_XY#.h#:s#\.cc$#.h#:s#\.[cC]$#.h#<CR> % 表示目前的檔名, 在 vim 打 :help :%s, 可看到 :%s 的用處, 它是用來取代檔名的指令, 功能同 s/.../.../, 特別的是, 它可以重覆使用。 原作者的巧思在於, 先將 .h 轉成一個大概不會出現的字串 (.X123X), 然後放心的將 .cpp 轉為 .h, 再將那個不會出現的字串轉回 .cpp。由於是字串代換, 代換的目標沒有出現, 也不會有不良影響。這裡的順序很重要, 替代字串的順序對的話, 就可應付各種情況。 所以要支援其它副檔名轉為 .h, 只要在後面直接多加 :s 即可。其它就只是細部小修改, 沒改也沒什麼影響。

執行檔和檔案路徑注意事項

daemon 執行的時候, 通常會在程式裡 chdir 到 / 再開始做事, 藉此避免之後 daemon 所在的目錄無法被砍掉 (即使從檔案系統上下指令砍掉該目錄, 實際上它仍存在, 要等 daemon 結束才會真的釋放)。 程式執行中若需要寫入一些暫存檔, 要考慮到權限問題, 可以寫到 /tmp 最省事, 若需要永久保留, 考慮寫到 $HOME/.PROG/ 下, 不要直接寫到執行檔目錄下。平時開發寫到執行檔目錄下沒有問題, 但當需要將程式打包成套件, 裝到系統目錄時 (如 /usr/bin、/usr/local/bin), 就會有權限問題而無法寫入。