發表文章

目前顯示的是有「idiom」標籤的文章

rule of three

rule of three or rule of five (額外多move). 此rule是根據rules of thumb in C++所產生 主要是為了預防再做資源管理時發生不可預期的錯誤, 所建議的撰寫規則. 如下為一個經由給定(=)後所產生的double free問題. #include <iostream> #include <string> class ResourceFreeFailed { private: char * m_str; public: ~ ResourceFreeFailed() { delete [] m_str; } ResourceFreeFailed() = default ; ResourceFreeFailed( const char * pstr) : m_str( new char [ 128 ]) { std :: strcpy(m_str, pstr); } }; int main () { ResourceFreeFailed c( "resource" ); { // d will release resource of c ResourceFreeFailed d; // ERROR: assign c to d d = c; } // c will release resource, but someting is wrong return 0 ; } [1][2]定義了兩種情況,在撰寫class時候需要記得此規則: 撰寫的class有需要自己做資源管理(resource management) 當撰寫以下其中一個成員函數時,需要一併明確定義其他成員函數 destructor copy constructor copy assignment operator move constructor (C+...

Pointer to Implementor(PIMPL)

概念 最近看到PIMPL的設計, 基於好奇就看了網路上的資訊. PIMPL主要的概念根據[1][2][3]可以分為兩點 (1)進一步的隱藏私有部分的成員變數及函數. 可以把所需的變數通通包在class Impl 裡面. (2)對於程式需要新增/刪除成員變數的時候,由於已改成Impl的方式.可以減少自己程式重新編譯的時間以及避免影響使用這些函式庫的程式因為ABI關係也重新編譯. 程式範例 work.hpp為一個外層handle的class. 主要是透過public的函數作為一個介面來呼叫實作在Impl的Class程式. line8~9是使用forward declaration.[4][5][6].所以必須使用pointer或reference的方式宣告Impl work.hpp 1 class Handle 2 { 3 public : 4 Handle(); 5 void CallA (); 6 7 private : 8 class Impl ; 9 Impl * m_Impl; 10 }; Line 4~8為Impl類別的實作. line 17則是handle類別透過CallA介面去呼叫實際實行的部分. work.cpp 1 #include < iostream > 2 #include "work.hpp" 3 4 class Handle :: Impl 5 { 6 public : 7 void DoA() { std :: cout << "Do A\n"; } 8 }; 9 10 Handle :: Handle() 11 { 12 m_Impl = new Impl; 13 } 14 15 void Handle :: CallA() 16 { 17 m_Impl -> DoA(); 18 } 19 20 int main() 21 ...

RAII 概念(Resource acquisition is initialization)

RAII 概念 RAII(Resource acquisition is initialization)中文即是"資源取得或分配即是在初始化". 看起來有點攏統. 個人的理解是RAII是用於object上的一個寫法. 物件建立的時候, 資源取得的是時候是經由constructor來初始. 結束的時候便透過destructor來釋放. 這樣的好處就是可以確保資源在物件的生命週期內是存在的. 結束的時候就會釋放掉資源. 閉免掉memory leak的問題或因為資源的關係導致程式運作不正常 C++程式範例 底下以[3]的程式作為範例, 如下所示. bad()會造成程式lock住. 而改為RAII的good()方式可以避免掉這問題. std :: mutex m; void bad() { m.lock(); // 直接取的 lock f(); // (1) 當有例外發生(exception), 程式鎖死 if ( ! everything_ok()) return ; // (2) 程式直接返回, 程式鎖死 m.unlock(); // 釋放lock } void good() { // 使用class包住lock. 而這邊不需像上述使用unlock. // 因為object結束會呼叫解構子. 會做unlok std :: lock_guard < std :: mutex > lk(m); f(); // (1) 當例外造成, lock object也會結束 if ( ! everything_ok()) return ; // (2) 程式返回, lock object也會結束 } // 正常結束, lock object也會結束 C結合RAII 因為之前寫C的時候, 每次都會為了malloc()跟free(), 讓程式碼不簡潔或造成編譯問題. (1) 如程式有重複的release資源的code. (2) 透過goto方式集中資源釋放, 但導致在goto之後的變數宣告無法初始數值 #include<stdio.h> #include<stdlib....