顯示具有 Programming 標籤的文章。 顯示所有文章
顯示具有 Programming 標籤的文章。 顯示所有文章

2011年5月30日 星期一

Boost 之 optional, assign 及 tribool

Boost 提供了一些小工具,讓程式碼可以更俱可讀性。

1. optional
    在寫程式時,常常會需要計算一些數值, 而這些數值有可能在某些條件下是沒有意義的,例如我們要算一個數的平方根時,一定得先檢查此數是否為非負數,若為負數,則此取平方根是沒有意義的(當然若是運算有考慮虛數則例外)。這時我們的程式片段大概長這樣:
    // double value = SOME_VALUE;
    ...
    if (value>=0) 
    {
       double sqrt_value = sqrt (value) ;
    }
    else
    {
        // error handling
    }
    
    這樣看起來其實沒什麼問題,但就設計哲學而言,client端 (sqrt函式的呼叫端) 必需先檢驗"條件",若通過後再真的"求值"。這樣的設計較為危險,因為 client必須去看文件,了解該函式的 domain 為何,再檢查 input 是否在該 domain 內,若是,再取值。把這樣的"知識"交由呼叫端來處理,可能帶來一些淺在的問題,例如呼叫端可能忘記檢查、可能檢查的條件是錯的,可能傳了負數進去得到了exception 卻沒處理,可能…。
    Boost 提供了一個小小的 wrapper class template 名為 boost::optional 來處理這種無意義值。使用上很簡單,client 以要封裝的 type 為 optional 的 template 參數宣告一個物件,將條件及求值式傳入 constructor。然後我們可以把這個 optional 物件像是測試 NULL pointer 一樣檢查其有效性 (支援 implicit conversion to bool),再用 operator* 取值 (因為 override 了 operator*) 。
    最後一步,就是在 library 端 (如果可以的話),或是 client 端寫個小小的 wrapper function 將條件封裝起來即可。
    #include<boost/optional.hpp>
    
    boost::optional<double> my_sqrt(double)
    {
       return boost::optional<double>(value>=0, sqrt(value)); 
    }
    
    void Foo( double value)
    {
       boost::optional<double> sqrt_value = my_sqrt( value );
       if(sqrt_value)
       {
          cout << *sqrt_value << endl;
       }
       else
       {
          cout << "value should not be negative." << endl;
       }
    }

    接著我們用 BOOST_AUTO 簡化一下程式碼,最後 client 就只要記得檢查 optional 是否有效,而不必知道如何檢查。
    #include<boost/optional.hpp>
    
    using namespace boost;
    
    optional<double> my_sqrt(double)
    {
       return optional<double>(value>=0, sqrt(value)); 
    }
    
    void Foo( double value)
    {
       BOOST_AUTO( sqrt_value, my_sqrt( value ));
       if(sqrt_value)
       {
          cout << *sqrt_value << endl;
       }
       else
       {
          cout << "value should not be negative." << endl;
       }
    }

    2. assign
    有時我們需要對 STL container 大量的塞一些常數性質的資料,像是 error code 或是 event messages 之類的,以往就是在程式裡寫一堆 push_back 或 insert。
    vector<int> v;
    v.push_back(1);
    v.push_back(3);
    v.push_back(4);
    v.push_back(7);
    v.push_back(9*9);
    
    map<int, string> m;
    m.insert ( make_pair ( 1, "one") );
    m.insert ( make_pair ( 2, "two") );
    m.insert ( make_pair ( 3, "three") );
    

    Boost 的 assign 函式庫實作了 "operator+="、逗號 "," 及 括號 "operator( )" 來簡化這些操作,下例結果同上。
    #include<boost/assign.hpp>
    using namespace boost::assign;
    
    vector<int> v;
    v += 1, 3, 4, 7, 9*9;
    
    map<int, string> m;
    m += make_pair ( 1, "one"), 
           make_pair ( 2, "two"), 
           make_pair ( 3, "three");
    
    

    使用 operator+= 在處理 map 時需要寫一大堆 make_pair,實在是很難看,我們可以用另一個 operator( ) 配合三個輔助函式insert( )、push_front( ) 及 push_back( ),更優雅地處理:
    #include<boost/assign.hpp>
    using namespace boost::assign;
    
    vector<int> v;
    push_back(v)(1)(3)(4)(7)(9*9);
    
    map<int, string> m;
    insert(m)( 1, "one")( 2, "two")( 3, "three");
    
    

    3. tribool
    一般我們在寫 C++ 要用到 Boolean 值時,通常有兩種型別可以用:BOOL 及 bool。由於早期的 C++ 並沒有 bool 這個關鍵字,所以各家 compiler 自行 typedef 或是 define 了 BOOL 這個型別 (或是 marco),通常它真正的型別是 int。例如微軟的 Windows API,而現代的 C++ (C99之後) 雖然加入了 bool 這個內建型別,但為了向下相容,Windows API 還是以 BOOL 來表示 Boolean 值。無論如何,現在應該儘量少用 BOOL 這個過時又不安全的東西了( 因為 BOOL 的值可能不為 TRUE 也不為 FALSE)。
    言歸正傳,bool 的 domain 應該只有 true 跟 false,這是廢話,但也因為這樣,我們無法用 bool 表示一個不確定的狀態。例如我們設一個 function 叫作 IsPrinterExists( ),用來偵測目前有沒有印表機存在,原型如下:
    bool IsPrinterExists();
    
    我們預期 IsPrinterExists( ) 應該回傳 true 表示有印表機,false 表示沒有,但如果偵測過程中有錯誤,那不管它回傳 true 或 false 都是不正確的(雖然設計上我們通常會當作 false 來處理,實務上大多也正確),應該要是一個 unknown 的值。
    Boost 引入一個新的型別,名為 tribool,它與 bool 差不多,但除了 true 跟 false 外還多了一個狀態 indeterminate。tribool 的 compare operation 有下列規則:
    • indeterminate 不是 true 也不是 false。
    • 任何與 indeterminate 比較的結果都是 indeterminate。
    • 對 || operator,只有與 true 的運算結果為 true,其它則為 indeterminate。
    • 對 && operator,只有與 false 的運算結果為 false,其它則為 indeterminate。
    • indeterminate 的 ! 運算結果還是 indeterminate。 
    • 可以使用 indeterminate( ) 來判斷是否為 indeterminate。 
    #include<boost/logic/tribool.hpp>
    
    using namespace boost;
    
    tribool tb(true);  // true
    tribool tb2(!tb)   // false
    
    if(tb)
    {
       // go here
       
       tb2 = indeterminate; // tb2 is indeterminate
       
       // OK, compare with indeterminate
       if( tb2 == indeterminate)
       {
          // go here
           cout << tb2 || true; // true
           cout << tb2 && false; // false
       }
       
       if(tb2)
           cout << "never printed";  // tb2 is not ture
       if(!tb2)
           cout << "never printed"; // tb2 is not false
       
       if( indeterminate(tb2) )
           cout << "indeterminate"; // yes
    }
    
    

    2011年5月6日 星期五

    C++0x 及 Boost 的自動型別推導:auto、decltype 及 BOOST_AUTO、BOOST_TYPEOF

    C++是個 static strong typing (靜態強型別) 的語言,因此所有變數在使用前都必須明確宣告其型別,這帶給了 C++ 執行快速的優點,並俱有較高的安全性。然而隨著 STL 及 自訂型別的大量使用,也帶來了一些寫程式上的小問題。

    舉例來說,我們常常要為 STL container 宣告 iterator 時,往往會寫這樣子的程式碼:

    std::map<int, std::string> myMap;
    ...
    ...
    std::map<int, std::string>::iterator itor = myMap.begin();
    // do something with itor

    其中我們的變數名稱只有四個字,而型別名稱卻有三十多字,若我們有許多這樣子的 container 及宣告,那程式碼中必然充斥著滿滿的宣告,而降低可讀性。對於這種問題,傳統的做法就是使用 typedef 或是 marco,但都只能解決一小部分的問題,就是程式碼看起來比較乾淨,但對於程式員而言,還是需要記得這冗長的型別名稱。myMap.begin( ) 回傳值的型別,你知我知 Compiler 也知,甚至在編譯期就可以確定了,那我們能夠少打這些多餘的字嗎?


    C++0x 提出了兩個關鍵字來解決這問題:auto 及 decltype。

    • auto 是個從 C 語言繼承而來的關鍵字,在 C++0x 之前,auto 是一種 storage-class specifiers,用來修飾變數宣告的 scope、lifetime 及 storage。如果一個變數的宣告前加上 auto 的話,那就表示是宣告一個 Local variable。如果一個變數宣告沒有加任何的 storage-class specifiers (如 static、register、extern …等),那預設就是auto。因為如此,auto 很少被使用。
      // Variable i is explicitly declared auto (local variable).
      auto int i = 0;
      // Variable j is implicitly declared auto (local variable).
      int j = 0; 
      在 VC2010 及 C++0x 中,auto 有了新的作用,用來表示一個經由 compiler 推導的型別 (Deduce Variable Type)。你可以在變數宣告前加上 auto 並給予初始值,該變數的型別會根據初始值來決定。可以被推導的型別有:const、volatile、pointer、reference 及 rvalue reference。
      我們可以在compile時加上參數。以選擇我們對於 auto 的使用方式:
      • /Zc:auto- : 表示將auto當成舊式的 storage-class specifiers
      • /Zc:auto (default): 表示將auto當成新式的 deduce variable type 

      // 宣告
      // Variable j is explicitly type int.
      int j = 0;
      // Variable k is implicitly type int because 0 is an integer.
      auto k = 0; 
      
      
      // 宣告 iterator (由其在loop裡)
      deque<double> dq1(2,0.1);
      
      for (auto it = dq1.begin(); it != dq1.end(); ++it)
      {  
          // do something
      }
      
      for_each(auto elem in dq1)
      {  
          // do something
      }
      
         
      // 宣告 pointer
      double x = 12.34;
      auto *y = new auto(x), **z = new auto(&x);
      
      
      // More
      auto x = 1, *y = &x, **z = &y; // Resolves to int.
      auto a(2.01), *b (&a);         // Resolves to double.
      auto c = 'a', *d(&c);          // Resolves to char.
      auto m = 1, &n = m;            // Resolves to int.
      
      
      // 搭配 :? 使用
      int v1 = 100, v2 = 200;
      auto x = v1 > v2 ? v1 : v2;
      
      
      // 搭配 const 使用
      int f(int x) { return x; }
      
      int main()
      {
          auto x = f(0);
          const auto & y = f(1);
          int (*p)(int x);
          p = f;
          auto fp = p;
          ...
      } 

      auto 雖然好用,但它並非萬能,以下為一些誤用 auto 的情況 (以下皆使用新式 auto,即 Compile with /Zc:auto )
      • 不能跟其它的 type-specifier 一起使用
       // error
      auto int x;
      • 用 auto 宣告變數必需給初始值
       // error
      auto x1;                 
      auto y1, y2, y3;         
      auto z1 = 1, z2, z3 = -1; 
      
      • auto 不可當作函式回傳型別, 亦不可當作 array 型別
       // error
      auto f( ){ }
      auto a[5];           
      auto b[1][2];        
      auto y[5] = x;       
      auto z[] = {1, 2, 3}; 
      auto w[] = x; 
      
      • auto 不可當作參數, 或 template 參數的型別
       // error
      void f(auto j){}
      
      template<class T> class C{};
      int main()
      {
         C<auto> c;   // C3539
         return 0;
      }
      
      • auto 搭配 new 使用時必需有初始值
       // error
      new auto();         
      auto x = new auto(); 
      
      • auto 不可被推導成 void, 亦不可宣告一個 auto pointer, 卻代入一物件(或內建型別)當初始值
       // error
      void f(){}
      auto x = f();
      
      auto* x = 123.0;
      
      class A { };
      A x;
      auto *p = x; 
      
      • 不可以該 auto 變數來自我初始化
      // error
      auto a = a;   
      auto b = &b;   
      auto c = c + 1; 
      auto* d = &d;  
      auto& e = e; 
      
      • 不可將其它型別轉型(cast)成 auto 型別
       // error
      auto(value);                      
      (auto)value;                     
      auto x1 = auto(value);            
      auto x2 = (auto)value;          
      auto x3 = static_cast<auto>(value); 
      
      • 在同一行所宣告的 auto 變數, 都必需被推導成同一型別
      // error
      // Variable x1 is a pointer to char, 
      // but y1 is a double.
      auto * x1 = "a", y1 = 3.14; 
      
      // Variable c is a char, 
      // but c1, c2, and c3 are pointers to pointers.
      auto c = 'a', *c1 = &c, * c2 = &c1, * c3 = &c2; 
      
      // Variable x2 is an int, 
      // but y2 is a double and z is a char.
      auto x2(1), y2(0.0), z = 'a'; 
      
      // Variable a is a pointer to int, 
      // but b is a pointer to double.
      auto *a = new auto(1), *b = new auto(2.0);
      
      • 不可對 auto 使用 sizeof 或 typeid
      auto x = 123;
      sizeof(x);    // OK
      sizeof(auto); // Error
      
      auto x = 123;
      typeid(x);    // OK
      typeid(auto); // Error
      

      • decltype 是 C++0x 新增的一個關鍵字,它接受一個 expression,並由該 expression 推導出一個型別。
      const int&& foo();
      int i;
      struct A { double x; };
      const A* a = new A();
      
      decltype(foo()) x1; // type is const int&&
      decltype(i) x2; // type is int
      decltype(a->x) x3; // type is double
      decltype((a->x)) x4; // type is const double&
      

      如今,auto 及 decltype 幾乎完全確定會制定於 C++0x當中了,但也是未來的 compiler 才會支援。這麼好用的東西,現在不能用實在是很可惜,所以 Boost 提供了兩個 marco 來模擬 auto 及 decltype。它們分別是BOOST_AUTO 及 BOOST_TYPEOF。
      • BOOST_AUTO 的用法為 BOOST_AUTO( Var, Expr),它會依 Expr 推導的型別宣告一個名為 Var 的變數,並初始化為 Expr 的值。
      • BOOST_TYPEOF 的用法為 BOOST_TYPEOF( Expr ),結果為一個經由推導 Expr 而成的型別指示詞 (Type specifier)。
      #include <boost/typeof/typeof.hpp>
      
      vector<string> func()
      {
          vector<string> v(10);
          return v;
      }
      
      int main()
      {
          BOOST_TYPEOF(2.0*3) x = 2.0*3;
          BOOST_AUTO(y, 2.3) ;
      
          BOOST_AUTO(&a, new double[20]);
          BOOST_AUTO(p, make_pair(1, "string"));
          BOOST_AUTO(v, func() );
          
          return 0;
      }
      

      參考資料:
      http://msdn.microsoft.com/en-us/library/dd465215.aspx
      http://www.boost.org/doc/libs/1_46_1/doc/html/typeof/tuto.html

      2011年5月5日 星期四

      Boost 之 smart pointer

      C++最令人苦惱的地方,不外乎就是語言特性太複雜( OO 及 Generic Programming 等等),以及缺乏自動記憶體管理。通常在寫C++時,我們會使用 RAII (Resource Acquisition Is Initialization) 這個 idiom (慣用手法) 來管理記憶體,也就是在物件的 constructor 中申請資源,然後在 destructor 釋放。但這僅僅於物件是建立在 stack 中 (Local variable)可行,若物件是建立於 heap 中,則 destructor 永遠不會被呼叫,除非我們手動 delete 它。

      為了更方便開發者管理記憶體,smart pointer 一直是C++陣營一直在探討的議題之一。而 C++98 中提供一個 smart point:auto_ptr
      auto_ptr 的 constructor 接受一個由 new operator 或是 object factory 所建立出的指標為參數,擁有這個指標所指的物件,並透過 override operator* 及 operator-> 來使其用起來像是一個真的指標。在 auto_ptr 退出其 scope 後,destructor 自然會被呼叫,而釋於資源。

      auto_ptr 解決了記憶體管理的問題,但它還不夠好用,最大的問題就是它對物件所有權的管理策略屬於 Destructive Copy,也就是一次只能有一個 auto_ptr 持有一個物件,禁止共享。

      std::auto_ptr<int> ptr1 ( new int (2) );
      std::auto_ptr<int> ptr2;
      ptr2 = ptr1 ; // transfer ownership from ptr1 to ptr2
      

      Boost.smart_ptr 基於 auto_ptr 擴充了六種適合不同需求所用的 smart pointers:
      1. scoped_ptr:類似 auto_ptr,但物件所有權無法轉移,因此同 auto_ptr,也無法被放到 STL container 中。另外,正如其名,我們只能在某個 scope 中使用它。
      2. scoped_array:scoped_ptr 的 array 版本,即內部是使用 new [ ] 及 delete [ ] 而非 new 與 delete。
      3. shared_ptr:是最類似 pointer 的 smart pointer,也是 Boost 中最有價值,最有用的組件。它實作了 reference count 機制,因此可以任何地方被 copy 及 assign value,當 reference count 為 0 時才會 delete 它。另外,shared_ptr 可以被使用於 STL container 中。
      4. shared_array:shared_ptr 的 array 版本。
      5. weak_ptr:一個用來協助 shared_ptr 的 smart pointer,通常它與 shared_ptr 共享同一個物件,但不會增加 reference count,因為它沒有 override operator* 及 operator->,因此也不會使用它來操作物件。它主要提供 use_count( ) 及 expired( ) 來回報 shared_ptr 的 reference count 以及內部指標是否有效等資訊。
      6. intrusive_ptr:一種侵入式的 smart pointer,由於 Boost 目前已不建議使用,因此也不多作介紹。
      詳細使用方法可參考 http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/smart_ptr.htm

      如果可以,請多多使用 shared_ptr 及 shared_array

      2008年7月27日 星期日

      A sample of template meta-programming

      C++ template 的發展動機其實很簡單,就是要增進程式碼的重覆利用性以及讓我們得以建立型別安全的容器,研究後最後發現,C++ template 機制本身是一部完整的 Turing-complete,可以被用來計算任何可以計算的值,進而衍生出 meta-programming 的概念。簡單說來,meta-programming 就是寫程式來產生程式碼 (由compiler產生,稱為俱現化,instantiation),再編譯成機器碼,這樣的好處就是可以把一些計算提到編譯時期處理,提高程式的效率也提早發現錯誤。通常拿來當作學習 C++ meta-programming 的程式大概就是階乘的計算,傳統上計算階乘的方法不是迭代法就是遞迴法,但這兩種方法都是在程式的執行時期才計算,以下簡單地給了非 meta-programming 版本以及 meta-programming 的版本,欣賞在編譯時就將數值計算完畢的神奇,也給對 meta-programming 有興趣的程式員一個入門的動力:

      傳統版:
      unsigned int Factorial (unsigned int n)
      {
      if ( n<=1 ) return 1 ;
      else return n*Factorial(n-1);
      }


      int main()
      {
      cout << Factorial (10) << endl ;
      return 0 ;
      }



      meta-programming 版:
      template<unsigned n>
      struct Factorial
      {
      enum { value = n * Factorial<n-1>::value } ;
      };


      template<>
      struct Factorial<0>
      {
      enum { value = 1 } ;
      };


      int main()
      {
      cout << Factorial<10>::value << endl ;
      return 0 ;
      }

      用 traits classes 以表現型別的資訊

      Traits classes 是一種在 STL 中廣泛應用的型別辨視技術,考慮以下情境,我們有四種自定型別 ClassA, ClassB, ClassC, ClassD,以及一個 function template F 如下:
      template<typename ClassT>
      void F( ClassT myType)
      {
      if ( myType is ClassA)
      {
      // operating for ClassA
      }
      else
      {
      // operaing for ClassB, C, D
      }
      }


      雖然 F 可以對這四種型別做運算,但有時候可能因為此四種型別的實作方式不一,某些型別對於 F 運算,可以有更有效率的作法 (或是不同的作法),例如 STL 中,對於某種 iterator 的運算,會因為 iterator 的不同類型 (STL 有五種 iterators:input, output, forward, bidirectional, random access) 而有不一樣的方法,所以我們希望能在 template 中辨視型別。

      首先我們建立一些 tag struct 用以表示型別的特徵:
      struct classA_tag {} ;

      struct classBCD_tag {} ;


      然後在目的型別中,利用 typedef 定義一個子型別
      class ClassA
      {
      public:
      typedef classA_tag category ;
      };


      class ClassB
      {
      public:
      typedef classBCD_tag category ;
      };


      class ClassC
      {
      public:
      typedef classBCD_tag category ;
      };


      class ClassD
      {
      public:
      typedef classBCD_tag category ;
      };


      接著,建立 traits class template:
      template<typename ClassT>
      struct MyTraits
      {
      typedef typename ClassT::category category;
      };


      此時我們的 function template F 大概變成這樣:
      template<typename ClassT>
      void F( ClassT myType)
      {

      if ( typeid (typename myTraits<ClassT>::category ) == typeid (classA_tag ) )
      {
      // operating for ClassA
      }
      else
      {
      // operaing for ClassB, C, D
      }
      }


      但是這樣的程式碼在編譯時可能會有問題 (因為 operating for ClassA 當中的所有敘述,必需被 ClassT 型別所支援,既使這些敘述不會被執行到),但此時有件更重要的事要解決,ClassT 也就是 myType 的型別在編譯時期就可以決定,而myTraits<ClassT>::category 也是在編譯時期就可以決定,但 if else 卻是執行期才會執行的語句,因此我們必須將 if else 提到編譯時期確定,做法即是使用 function overloading。我們 overload 兩個 function template F如下:
      template<typename ClassT>
      void doF( ClassT myType, classA_tag)
      {
      // operaing for ClassA
      }


      template<typename ClassT>
      void doF( ClassT myType, classBCD_tag)
      {
      // operaing for ClassB, C, D
      }


      最後,我們就可以將 F 改寫如下:
      template<typename ClassT>
      void F( ClassT myType)
      {
      doF ( myType , typename MyTraits<ClassT>::category( ) );
      }


      完工。

      2008年7月17日 星期四

      WinAPI型別與.NET型別的對照表

      http://www.codeproject.com/KB/dotnet/Win32APICPlusPlustoDotNET.aspx

      http://msdn.microsoft.com/zh-tw/library/hfa3fa08(VS.80).aspx

      雖然.NET的函式庫已經應有儘用,但有時還是會到別人給的dll檔,而這些dll檔通常都是用VC++所寫的,要使用的話,就必須自已依C++標頭檔重新宣告函式。這個表就是在作型別轉換時必備的資訊。

      2008年7月16日 星期三

      F# Programming Language

      http://research.microsoft.com/fsharp/fsharp.aspx

      F# 是微軟新推出的程式語言,最大的特色就是他是函數式程式語言(Functional Programming Language),以往函數編程最大的缺點就是效率太差,但今日硬體的進步與多核心CPU的流行,反而讓函數編程佔了優勢,所以微軟立即推出F#以吸引程式員。微軟在官方首頁上形容F#為:

      Combining the efficiency, scripting, strong typing and productivity of ML with the stability, libraries, cross-language working and tools of .NET.

      給了F#一個很大的評價,也說明了函數編程,必然是未來的趨勢。

      TIOBE Programming Community Index for July 2008

      http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html

      身為一個專業的程式設計師,至少前十名也要會個七八樣。

      2008年5月28日 星期三

      [Note] MSP430 interrupt vector

      DACDMA_VECTOR
      PORT2_VECTOR
      USART1TX_VECTOR
      USART1RX_VECTOR
      PORT1_VECTOR
      TIMERA1_VECTOR
      TIMERA0_VECTOR
      ADC12_VECTOR
      USART0TX_VECTOR
      USART0RX_VECTOR
      WDT_VECTOR
      COMPARATORA_VECTOR
      TIMERB1_VECTOR
      TIMERB0_VECTOR
      NMI_VECTOR

      2008年5月13日 星期二

      .NET 的 Task Parallel Library

      近幾年來多核心CPU日漸普及,從雙核心、四核心到八核心,意味著現在的CPU可以一次執行多道指令,但計算機結構教科書上所提及的pileline三大hazard,與軟體設計的不良,卻使得多核心CPU效能無法被完全發揮。而就軟體來看,雖然設計了multi-threads,但若沒有搭配平行處理的函式庫,程式多半還是以單一核心在執行。在C++中,有著著名的OpenMP函式庫可供使用,但在.NET平台上CLR與Threading類別庫的設計,卻沒考慮到多核心的問題,以致效能不彰。但微軟也發現了這個大問題,成立了平行運算部門來開發新的CLR,並在去年年底發表了 Task Parallel Library測試版本,但這個library的用法必需手動地指明要平行運算的方式,與OpenMP只要指明那個指令想平行運算,compiler就會自動幫你規畫不太一樣,雖然要改寫的code不多,但若能自動的偵測,似乎比較完善。

      2008年3月28日 星期五

      [note] Qualified name 與 Dependent name

      這是 C++ template 中對於名稱的兩個最主要的命名方式,

      Qualified name:當一個名稱被以 :: 或 . 或 -> 給指明其作用域時,這個名稱稱為 qualified name (受飾名稱)

      Dependent name: 當一名稱受控於某個 template parameter 時,這個名稱稱為 dependent name (受控名稱),例如 T 是個 template parameter 時,std::vector<T>::iterator 為一個 dependent name;而當 T 是個已知型別時(如 int),則 std::vector<T>::iterator 為一個 nondependent name。

      參考自 C++ Templates 全覽 (侯捷譯)

      2008年3月24日 星期一

      C++ Templates 的源碼檔案組織方式

      在傳統的 C/C++ 程式設計中,我們通常把型別及函式的宣告式放在表頭檔 ( *.h header files),定義式放在實作檔 (*.c *.cpp)中,但是這種運作方式在 C++ templates 中會讓聯結器不能正常工作,因為函式的定義與宣告被放置於兩個不同的檔案,使得該 template function 無法被俱現化,解決的方式大概可分成三個:

      1. Inclusion Model:將函式的定義直接寫在 header file,這也是最佳的處理方法。

      2. Explicit Instantiation:新增一檔案,加入明確俱現化 template 的敘述,並引入實作檔。

      3. Separation Model:使用 export 關鍵定,將 template 匯出。

      2008年3月14日 星期五

      [Note] gcc 中 ISR 及 SIGNAL 的差別

      筆記一下,

      ISR 與 SIGNAL 都是用來指定 interrupt service routine 的巨集,

      它們的差別就是:沒有差別。

      SIGNAL 是舊的寫法,也就是為了相容舊的程式碼而保留下來的,

      在寫新的 code 時,請用 ISR

      2008年2月16日 星期六

      程式員四大忌

      從 iThome 看到的,原文是 JavaResearch 的文章:

      1. 輕易言敗,沒有自信

      2. 浮華不實,自滿自大

      3. 死氣沉沉,不求甚解

      4. 強調客觀,忽略自身

      2008年2月15日 星期五

      用 Visual Studio 2005 開發俱 UAC 機制軟體

      Microsoft 在 Windows Vista 中新增了一個重要的安全機制,就是 User Account Control (UAC),也就是軟體在執行會用到受保護的資源時,會跳出一個對話方塊詢問是否執行,確定後就會以 Administrator 身份來執行程式,雖然麻煩了一點,不過也帶來可靠的安全性,然而在 Visual Studio 2005 中要怎麼使用這個機制呢?

      1. 首先,開啟專案屬性的頁面, 在安全性這個分頁中,將 "啟用 ClickOnce 安全性設定" 勾選,然後在方案總管中就會出現一個名為 app.manifest 的檔案

      2. 編輯 app.manifes,在 <security> 與 </security> 中,加入以下項目:
      <requestedPrivileges>
      <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
      </requestedPrivileges>

      其中 level 的值可以是:

      asInvoker:不要求權限,使用 parent process 的權限。
      highestAvailable:要求 parent process 的最高權限。
      requireAdministrator:要求 Administrator 權限。

      3. 存檔後重新編譯,產生的執行檔就俱有 UAC 機制了。

      2008年2月9日 星期六

      [Note] PHP6 去除的功能

      這篇也是從 RunPC 上看來的,因為 PHP4 已停止維護 (請見...),有考慮要升級到 PHP6 的網管人員們可別太衝動,因為 PHP6 移除了一些東西,在升級之前可能要先測試一下原本的 Code 能不能在 PHP6 中運作,以下為移除的項目:

      1. register_globals
      這大概是最嚴重的,原本只要把 register_globals 設成 On,就可以很自由地存取全域變數,無論它是從何而來,而現在取消了這項功能,程式員必須很清楚地指明變數的來源,雖然會帶來很多麻煩,卻帶來了安全。

      2. register_long_array 與 $HTTP_*_VARS
      取消了  register_long_array 的設定,並連帶取消 $HTTP_GET_VARS 及 $HTTP_POST_VARS 變數。

      3. Magic Quotes
      原本若開啟 magic quotes,則系統會幫你的特殊字元加上 '\' ,不過這是在過去為了處理中文字需要的,PHP6 已全面使用 unicode,自然就不需要 Magic Quotes

      4. safe_mode
      取消 Safe Mode,必免讓程式員誤解它的功能。

      [Note] String 與 StringBuilder 之效能

      .NET Framework SDK 中提供了另一種特別的 String 類別,其名為 StringBuilder,當你有大量字串要"連接"起來時,可以使用 StringBuilder 來提昇效能,因為如果你宣告一個 String 變數並給它值,日後要改變值的話,就要放棄原本的那塊記憶體,而再配置一塊新的記憶體來存放新值,如果改變值的動作很頻繁則會大大地降低效能,而 StringBuilder 就是用來解決這個問題。

      這期的 RunPC 做了個實驗來比較兩者的差異,一開始原作者分別使用 String 與 StringBuilder 來連接大量的靜態子字串如下,結果效能居然是 String 較佳,而差異大概有十倍,這是怎麼回事呢。原因在於我們連結接是靜態的字串,Compiler 在 編譯時期就會幫他們做最佳化,而連接在一起,所以 String 的 Case 等於什麼都做,當然比 StringBuilder 快很多,接著我們改成動態字串 (Run Time 才決定的字串),效能比較就如我們預期,由 StringBuilder 獲勝。

      因此,在你決定用 String 或 StringBuilder 時,最好先考慮一下字串被"決定"的 時機,在 Compile Time 或是 Run Time 呢?
      public string ConnectStrings_string( )
      {
      string tmp = "" ;

      tmp += "11111111111111111111111111111111111111111111111111111111111"  ;

      tmp += "2222222222222222222222222222222222222222222222222222"   ;

      tmp += "3333333333333333333333333333333333333333333333333333"  ;

      // 中間略

      tmp += "100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100"  ;

      return tmp ;

      }

      public string ConnectStrings_stringbuilder( )
      {
      StringBuilder tmp = "" ;

      tmp.Append( "11111111111111111111111111111111111111111111111111111111111"  );

      tmp.Append( "2222222222222222222222222222222222222222222222222222"  ) ;

      tmp.Append( "3333333333333333333333333333333333333333333333333333"  );

      // 中間略

      tmp.Append( "100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100" ) ;

      return tmp.ToString( ) ;

      }

      2007年12月24日 星期一

      [note] More Effective C++ 2/e (3)

      item 25:Virtualizing constructors and non-member functions
      將 constructors 及 non-member functions 的行為虛擬化。

      item 26:Limiting the number of objects of a class
      限制 class 能產生的物件數量。

      item 27:Requiring or prohibiting heap-base objects
      了解要求或禁止物件產生在 heap space 的手法。

      item 28:Smart Pointers
      了解 smart pointer (auto_ptr) 的用法。

      item 29:Reference counting
      了解 reference counter 的實作手法。

      item 30:Proxy classes
      了解 proxy class 的用法。

      item 31:Making functions virtual with respect to more than one object
      讓函式可以根據一個以上的物件型別來決定如何虛擬化。

      item 32:Program in the future tense
      在未來時態下開發程式:提供完整的 class、設計容易被正確運用的 class、儘量使 code 一般化。

      item 33:Make non-leaf classes abstract
      如果有一個俱象類別 C 繼承另一個俱象類別 B,應該想辦法提煉出抽象類別 A,使 B 和 C 都繼承自 A。

      item 34:Understand how to combine C++ and C in the same program
      了解在 C++ 中使用 C 函式所會引發的問題,如 Name Mangling、Statics initialize、dynamic memory allocation 和資料結構的相容性。

      item 35: Familiarize yourself with the language standard
      儘可能地習慣 C++ 語言。

      [note] More Effective C++ 2/e (2)

      item 9:Use destructors to prevent resource leaks
      使用 auto_ptr 配合 destructor,避免在 exception 發生時產生 resource leak。

      item 10:Prevent resource leaks in constructors
      注意 constructor 裡發生 exception 時,是否會產生 resource leak 及避免之。

      item 11:Prevent exceptions from leaving destructors
      當 destructor 產生 exception 時,別讓它被丟出 destructor (一定要處理之)。

      item 12:Understand how throwing an exception differs from passing a parameter or calling a virtual function
      了解丟出 exception 與傳遞一個參數或呼叫虛擬函式的不同。

      item 13:Catch exceptions by reference
      用 by reference 的方式來取得 exception。

      item 14:Use exception specifications judiciously
      明智地使用 exception specifications。

      item 15:Understand the costs of exception handling
      了解 exception handling 的成本。

      item 16:Remember the 80-20 rule
      讓 80% 的時間都在執行 20% 的程式碼。

      item 17:Consider using lazy evaluation
      考慮使用 lazy evaluation (拖挺戰術)。

      item 18:Amortize the cost of expected computations
      分期償還期的計算成本。

      item 19:Understand the origin of temporary objects
      了解暫時物件的產生時機。

      item 20:Facilitate the return value optimization
      了解並會協助 compiler 做 return value optimization。

      item 21:Overload to avoid implicit type conversions
      使用 overloding 技術來取代隱型轉型

      item 22:Consider using op= instead of stand-alone op
      使用 op= 來完成 op 的動作,例如使用 += 來完成 +。

      item 23:Consider alternative libraries
      考慮使用更理想的函式庫。

      item 24: Understanding the costs of virtual functions, multiple inheritance, virtual base classes, and RTTI
      了解虛擬函式、多重繼承、虛擬繼承及 RTTI 的成本。

      2007年12月12日 星期三

      [note] More Effective C++ 2/e (1)

      item 1:Distinguish between pointers and references
      了解 pointer 及 reference 的差異。

      item 2:Prefer C++-style casts
      使用 C++ 的轉型。

      item 3:Never treat arrays polymorphically
      別以多型的方式來處理陣列。

      item 4:Avoid gratuitous default constructors
      非必要不提供 default constructors。

      item 5:Be wary of user-defined conversion functions
      小心隱式轉型所帶來的危險 ( 以explicit禁止之 )。

      item 6:Distinguish between prefix and postfix forms of increment and decrement operators
      了解前置式累加(減)與後置式累加(減)的本質及差異。

      item 7:Never overload &&, ||, or ,
      不覆寫 && || 及 ,,否則會影響傳統上 compiler 對於條件式的 short-circuit 特性。

      item 8:Understand the difference meanings of new and delete
      了解不同意義的 new 與 delete,如 new operator、operator new 及 placement new。