「トップページ/CPP」の編集履歴(バックアップ)一覧はこちら

トップページ/CPP」(2009/02/02 (月) 21:52:11) の最新版変更点

追加された行は緑色になります。

削除された行は赤色になります。

|&big(){C++いろいろ}| #contents() ---- *コンテナを戻り値にしても大丈夫か? class Array : public vector<int> { public: Array() { push_back(0); printf("コンストラクタ[%p, %p]\n", this, &at(0)); } public: Array(Array& arr) : vector(arr){ printf("コピーコンスト[%p, %p]\n", this, &at(0)); } public: virtual ~Array() { printf("デストラクタ [%p, %p]\n", this, &at(0)); vector::~vector(); } }; Array Sub(void) { Array arr; // スタックにインスタンスを作って return arr; // それをそのまま返してみる } void Run(void) { puts("IN"); Array arr(Sub()); puts("NEXT"); arr = Sub(); puts("OUT"); } int _tmain(int argc, _TCHAR* argv[]) { Run(); getchar(); return 0; } 実行結果 IN <-- RUNに入ったとき コンストラクタ[0012FD3C, 0039A6E0] 確保 コピーコンスト[0012FE6C, 0039A720] : 確保 デストラクタ [0012FD3C, 0039A6E0] 解放 : NEXT <-- : コンストラクタ[0012FD3C, 0039A6E0] 確保 : コピーコンスト[0012FD8C, 0039A760] : : 確保 デストラクタ [0012FD3C, 0039A6E0] 解放 : : デストラクタ [0012FD8C, 0039A760] : 解放 OUT <--RUNから出るとき : デストラクタ [0012FE6C, 0039A720] 解放 もしかして中身はそのままでアドレスのみコピーかと思ったが、まるごとのコピーが発生する。 ただし、動作に問題はない。メモリリークは発生しない。 今度は、shared_ptrで実験してみる。mainとclass Arrayはさっきと同じ boost::shared_ptr<Array> Sub(void) { boost::shared_ptr<Array> p = boost::shared_ptr<Array>(new Array()); return p; } void Run(void) { puts("IN"); boost::shared_ptr<Array> parr(Sub()); puts("NEXT"); parr = Sub(); puts("OUT"); } 実行結果 IN <-- RUNに入ったとき コンストラクタ[00348BB8, 00348C10] 確保 NEXT : コンストラクタ[00344C48, 00344CA0] : 確保 デストラクタ [00348BB8, 00348C10] 解放 :    <--!! OUT <-- RUNから出るとき : デストラクタ [00344C48, 00344CA0] 解放 見事に理想通りの動作をした。 parr = Sub()の行で、最初に確保したArrayを指すものがなくなると きちんと解放されている。 shared_ptr<array>は、typedefしておこう。 ---- *8bit×4パックド飽和加算  いまさらですが、32ビット変数を用いて8ビット×4のパックド飽和加算をしてしまう!というコードを検証してみました。  意外なことに、テストをパスできたコードがありませんでした(@@  いまどき、SSE2の使えないCPUを使うことはほとんどありませんが、組み込みでは非インテルなこともあるので、残念な結果になりました。 //(Haya様HPより) // 合計が256になったとき、0になってしまう(255が正解)。 時々、合計が1多くなる Int32 AddBlend(Int32 a, Int32 b) { Int32 m = (0x80808080 - ((((a >> 1) & 0x7f7f7f7f) + ((b >> 1) & 0x7f7f7f7f) + ((a ^ b) & 0x01010101)) >> 7 & 0x01010101)) ^ 0x80808080; return (a & (~m)) + (b | m); } //(Kouhei Yanagita様HPより) // 最上位バイトが飽和せず、折り返してしまう Int32 AddBlend(Int32 a, Int32 b) { Int32 c = ((a & b) + (((a ^ b) >> 1) & 0x7f7f7f7f)) & 0x80808080; Int32 m = (c << 1) - (c >> 7); return ((a + b) - m) | m; } // (やねうらお様HPより) // 最上位バイトが飽和せず、折り返してしまう Int32 AddBlend(Int32 a, Int32 b) { Int32 c = ((( a & b )<<1) + ((a ^ b) & 0xfefefe)) & 0x1010100; Int32 m = c - (c>>8); return (a + b - c) | m; } // テスト親プログラム int main(array<System::String ^> ^args) { Byte array32s1[4] = {1,2,3,4}; Byte array32s2[4] = {3,4,5,6}; Byte array32sa[4]; Random^ rand = gcnew Random(); int errcnt = 0; for (int i = 0 ; i < 10000 ; i ++ ) { // 初期値を入れる for (int j = 0 ; j < 4 ; j++ ) { array32s1[j] = rand->Next(0,255); array32s2[j] = rand->Next(0,255); } // 実行 *(reinterpret_cast<Int32*>(array32sa)) = AddBlend(*(reinterpret_cast<Int32*>(array32s1)), *(reinterpret_cast<Int32*>(array32s2))); // テスト int isTestError = 0; // ==false for (int j = 0 ; j < 4 ; j++ ) { int a = array32s1[j] + array32s2[j]; if (a > 255) a = 255; if (a != array32sa[j]) isTestError |= (1<<j); } if (isTestError) { Console::WriteLine( i.ToString("d5") + "------------------------"); for (int j = 0 ; j < 4 ; j++ ) Console::Write(" "+array32s1[j].ToString("d3")+" "); Console::WriteLine(); for (int j = 0 ; j < 4 ; j++ ) Console::Write(" "+array32s2[j].ToString("d3")+" "); Console::WriteLine(); for (int j = 0 ; j < 4 ; j++ ) { if (isTestError & (1<<j)) { Console::Write("<"+array32sa[j].ToString("d3")+"> "); errcnt ++; } else { Console::Write(" "+array32sa[j].ToString("d3")+" "); } } Console::WriteLine(""); } } // 結果表示 if (errcnt==0) Console::WriteLine("pass!"); else Console::WriteLine("error = " + errcnt.ToString() ); Console::ReadLine(); return 0; }  ほかにもこんなのが掲載されていました。(未検証) // (やねうらお様HPより) // 平均 Int32 Ave(Int32 a, Int32 b) { return (a&b) + (((a^b) & 0xfefefefe) >> 1); } // 飽和インクリメント Int32 Inc(Int32 a) { Int32 num = ((~(a & ((a & 0x7f7f7f7f) + 0x01010101 ))) & 0x80808080) >> 7; return a + num; } // 飽和デクリメント Int32 Dec(Int32 a) { Int32 num = ((x | ((x | 0x80808080) - 0x01010101)) & 0x80808080 >> 7; retrun a - num; } // 比較 Int32 Cmp(Int32 a, Int32 b) { Int32 c = a^b; c = (((c & 0x7f7f7f7f) + 0x7f7f7f7f) | c) & 0x80808080; c |= c - (c >> 7); retrun ~c; } // 左シフト(16ビット) Int32 ShlW(Int32 x, Int32 s) { Int32 m = 0xffff0000 ~ (0x0000ffff < s) } ---- *整数の絶対値 inline Int32 fastabs(Int32 a) { Int32 m = a >> 31; return (a ^ m) - m; } *2整数のmax, min inline Int32 fastmax(Int32 a, Int32 b) { Int32 t = (a-b); return a - (t & (t >> 31)); } inline Int32 fastmin(Int32 a, Int32 b) { Int32 t = (a-b); return b + (t & (t >> 31)); } ---- *16進文字列を数値にする string str = "0xcdef"; int a = 0; try { a = boost::lexical_cast<int>(str); } catch(boost::bad_lexical_cast&) { ; } ---- *構造体メンバの先頭からのオフセットを得る #include <stddef.h> size_t offsetof( type, member); ---- *コールバックの実装(Boost) Runメソッドを呼ぶと、testEventに登録された関数が呼ばれる。 testEventメンバをpublicにせず、SetTestEventメソッド経由にする理由は、外部からイベントハンドラを呼ぶことが出来てしまうからである。SetTestEventメソッドの引数にNULLを渡すと、イベントハンドラをクリアする事が出来る。 // 呼び出し元 class aa { // イベントハンドラ(イベント発生時に呼び出す関数のアドレス) protected: boost::function<string (int a,int b)> testEvent; // 内部からイベントハンドラを呼び出す為のラッパー protected: virtual string OnTestEvent(int a, int b) { string retstr; if (testEvent!=NULL) retstr=testEvent(a,b); return retstr; } // イベントハンドラを登録する public: void SetTestEvent(boost::function<string (int a,int b)> func) { testEvent = func; } public: void Run(void) { cout << "[" << OnTestEvent(5,8) << "]" << endl; } } // 呼び出し先 class bb { protected: string TestEventFunc(int a, int b) { return boost::io::str(boost::format("a+b=%d") % a+b); } } // int main(int, char**) { aa AA; bb BB; AA.SetTestEvent( boost::bind(&bb::TestEventFunc, &BB, _1, _2); AA.Run(); return 0; }
|&big(){C++いろいろ}| #contents() ---- *コンテナを戻り値にしても大丈夫か? 最もよく使うstlのvectorで実験してみる。 class Array : public vector<int> { public: Array() { push_back(0); printf("コンストラクタ[%p, %p]\n", this, &at(0)); } public: Array(Array& arr) : vector(arr){ printf("コピーコンスト[%p, %p]\n", this, &at(0)); } public: virtual ~Array() { printf("デストラクタ [%p, %p]\n", this, &at(0)); vector::~vector(); } }; Array Sub(void) { Array arr; // スタックにインスタンスを作って return arr; // それをそのまま返してみる } void Run(void) { puts("IN"); Array arr(Sub()); puts("NEXT"); arr = Sub(); puts("OUT"); } int _tmain(int argc, _TCHAR* argv[]) { Run(); getchar(); return 0; } 実行結果 IN <-- RUNに入ったとき コンストラクタ[0012FD3C, 0039A6E0] 確保 コピーコンスト[0012FE6C, 0039A720] : 確保 デストラクタ [0012FD3C, 0039A6E0] 解放 : NEXT <-- : コンストラクタ[0012FD3C, 0039A6E0] 確保 : コピーコンスト[0012FD8C, 0039A760] : : 確保 デストラクタ [0012FD3C, 0039A6E0] 解放 : : デストラクタ [0012FD8C, 0039A760] : 解放 OUT <--RUNから出るとき : デストラクタ [0012FE6C, 0039A720] 解放 もしかして中身はそのままでアドレスのみコピーかと思ったが、まるごとのコピーが発生する。 ただし、動作に問題はない。メモリリークは発生しない。 今度は、shared_ptrで実験してみる。mainとclass Arrayはさっきと同じ boost::shared_ptr<Array> Sub(void) { boost::shared_ptr<Array> p = boost::shared_ptr<Array>(new Array()); return p; } void Run(void) { puts("IN"); boost::shared_ptr<Array> parr(Sub()); puts("NEXT"); parr = Sub(); puts("OUT"); } 実行結果 IN <-- RUNに入ったとき コンストラクタ[00348BB8, 00348C10] 確保 NEXT : コンストラクタ[00344C48, 00344CA0] : 確保 デストラクタ [00348BB8, 00348C10] 解放 :    <--!! OUT <-- RUNから出るとき : デストラクタ [00344C48, 00344CA0] 解放 見事に理想通りの動作をした。 parr = Sub()の行で、最初に確保したArrayを指すものがなくなると きちんと解放されている。 shared_ptr<array>は、typedefしておこう。 ---- *8bit×4パックド飽和加算  いまさらですが、32ビット変数を用いて8ビット×4のパックド飽和加算をしてしまう!というコードを検証してみました。  意外なことに、テストをパスできたコードがありませんでした(@@  いまどき、SSE2の使えないCPUを使うことはほとんどありませんが、組み込みでは非インテルなこともあるので、残念な結果になりました。 //(Haya様HPより) // 合計が256になったとき、0になってしまう(255が正解)。 時々、合計が1多くなる Int32 AddBlend(Int32 a, Int32 b) { Int32 m = (0x80808080 - ((((a >> 1) & 0x7f7f7f7f) + ((b >> 1) & 0x7f7f7f7f) + ((a ^ b) & 0x01010101)) >> 7 & 0x01010101)) ^ 0x80808080; return (a & (~m)) + (b | m); } //(Kouhei Yanagita様HPより) // 最上位バイトが飽和せず、折り返してしまう Int32 AddBlend(Int32 a, Int32 b) { Int32 c = ((a & b) + (((a ^ b) >> 1) & 0x7f7f7f7f)) & 0x80808080; Int32 m = (c << 1) - (c >> 7); return ((a + b) - m) | m; } // (やねうらお様HPより) // 最上位バイトが飽和せず、折り返してしまう Int32 AddBlend(Int32 a, Int32 b) { Int32 c = ((( a & b )<<1) + ((a ^ b) & 0xfefefe)) & 0x1010100; Int32 m = c - (c>>8); return (a + b - c) | m; } // テスト親プログラム int main(array<System::String ^> ^args) { Byte array32s1[4] = {1,2,3,4}; Byte array32s2[4] = {3,4,5,6}; Byte array32sa[4]; Random^ rand = gcnew Random(); int errcnt = 0; for (int i = 0 ; i < 10000 ; i ++ ) { // 初期値を入れる for (int j = 0 ; j < 4 ; j++ ) { array32s1[j] = rand->Next(0,255); array32s2[j] = rand->Next(0,255); } // 実行 *(reinterpret_cast<Int32*>(array32sa)) = AddBlend(*(reinterpret_cast<Int32*>(array32s1)), *(reinterpret_cast<Int32*>(array32s2))); // テスト int isTestError = 0; // ==false for (int j = 0 ; j < 4 ; j++ ) { int a = array32s1[j] + array32s2[j]; if (a > 255) a = 255; if (a != array32sa[j]) isTestError |= (1<<j); } if (isTestError) { Console::WriteLine( i.ToString("d5") + "------------------------"); for (int j = 0 ; j < 4 ; j++ ) Console::Write(" "+array32s1[j].ToString("d3")+" "); Console::WriteLine(); for (int j = 0 ; j < 4 ; j++ ) Console::Write(" "+array32s2[j].ToString("d3")+" "); Console::WriteLine(); for (int j = 0 ; j < 4 ; j++ ) { if (isTestError & (1<<j)) { Console::Write("<"+array32sa[j].ToString("d3")+"> "); errcnt ++; } else { Console::Write(" "+array32sa[j].ToString("d3")+" "); } } Console::WriteLine(""); } } // 結果表示 if (errcnt==0) Console::WriteLine("pass!"); else Console::WriteLine("error = " + errcnt.ToString() ); Console::ReadLine(); return 0; }  ほかにもこんなのが掲載されていました。(未検証) // (やねうらお様HPより) // 平均 Int32 Ave(Int32 a, Int32 b) { return (a&b) + (((a^b) & 0xfefefefe) >> 1); } // 飽和インクリメント Int32 Inc(Int32 a) { Int32 num = ((~(a & ((a & 0x7f7f7f7f) + 0x01010101 ))) & 0x80808080) >> 7; return a + num; } // 飽和デクリメント Int32 Dec(Int32 a) { Int32 num = ((x | ((x | 0x80808080) - 0x01010101)) & 0x80808080 >> 7; retrun a - num; } // 比較 Int32 Cmp(Int32 a, Int32 b) { Int32 c = a^b; c = (((c & 0x7f7f7f7f) + 0x7f7f7f7f) | c) & 0x80808080; c |= c - (c >> 7); retrun ~c; } // 左シフト(16ビット) Int32 ShlW(Int32 x, Int32 s) { Int32 m = 0xffff0000 ~ (0x0000ffff < s) } ---- *整数の絶対値 inline Int32 fastabs(Int32 a) { Int32 m = a >> 31; return (a ^ m) - m; } *2整数のmax, min inline Int32 fastmax(Int32 a, Int32 b) { Int32 t = (a-b); return a - (t & (t >> 31)); } inline Int32 fastmin(Int32 a, Int32 b) { Int32 t = (a-b); return b + (t & (t >> 31)); } ---- *16進文字列を数値にする string str = "0xcdef"; int a = 0; try { a = boost::lexical_cast<int>(str); } catch(boost::bad_lexical_cast&) { ; } ---- *構造体メンバの先頭からのオフセットを得る #include <stddef.h> size_t offsetof( type, member); ---- *コールバックの実装(Boost) Runメソッドを呼ぶと、testEventに登録された関数が呼ばれる。 testEventメンバをpublicにせず、SetTestEventメソッド経由にする理由は、外部からイベントハンドラを呼ぶことが出来てしまうからである。SetTestEventメソッドの引数にNULLを渡すと、イベントハンドラをクリアする事が出来る。 // 呼び出し元 class aa { // イベントハンドラ(イベント発生時に呼び出す関数のアドレス) protected: boost::function<string (int a,int b)> testEvent; // 内部からイベントハンドラを呼び出す為のラッパー protected: virtual string OnTestEvent(int a, int b) { string retstr; if (testEvent!=NULL) retstr=testEvent(a,b); return retstr; } // イベントハンドラを登録する public: void SetTestEvent(boost::function<string (int a,int b)> func) { testEvent = func; } public: void Run(void) { cout << "[" << OnTestEvent(5,8) << "]" << endl; } } // 呼び出し先 class bb { protected: string TestEventFunc(int a, int b) { return boost::io::str(boost::format("a+b=%d") % a+b); } } // int main(int, char**) { aa AA; bb BB; AA.SetTestEvent( boost::bind(&bb::TestEventFunc, &BB, _1, _2); AA.Run(); return 0; }

表示オプション

横に並べて表示:
変化行の前後のみ表示: