私とC++ in 例外安全day

1,368 views
1,177 views

Published on

0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,368
On SlideShare
0
From Embeds
0
Number of Embeds
166
Actions
Shares
0
Downloads
2
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

私とC++ in 例外安全day

  1. 1. 私とC++ In 例外安全Day
  2. 2. 自己紹介 石川達也 株式会社Codeer代表取締役 C, C++, C#, Java
  3. 3. Exceptional C++ 読書会で 常識のある人間です。
  4. 4. Exceptional C++ 読書会で 常識のある人間です。 ・gotoを使わない。
  5. 5. Exceptional C++ 読書会で 常識のある人間です。 ・gotoを使わない。 ・Duff‘s deviceなどもっての 外。
  6. 6. Exceptional C++ 読書会で 常識のある人間です。 ・gotoを使わない。 ・Duff‘s deviceなどもっての 外。 ・VC++をDisらない。
  7. 7. 今日は、 体験談を語らせてもらいます。 参考にするもよし、 マサカリ投げるもよし。 (優しく)
  8. 8. アジェンダ ・例外 ・テンプレート活用例 ・関数ポインタキャスト ・アロケータ記憶 ・AOPもどきログ
  9. 9. 例外 ・リソース系 ・プログラムミス系
  10. 10. 例外 注)OutOfMemory 場合によって・・・ リソース系 or プログラムミス系
  11. 11. 例外に関する姿勢 ・リソース系 FileIO 他の機器との通信 例外安全に作ります。 最終的には、catchして適切に処 理。 て言うか、例外とは思っていない。
  12. 12. 例外に関する姿勢 ・プログラムミス (ASSERT含む) 問題はこれ。
  13. 13. 例外(プログラムミス) std::vector<int> buf; ・・・ buf[index] = 100; //範囲外とか。
  14. 14. 例外(プログラムミス) swtich(val) { ・・・ default://予期せぬ値とか。 ASSERT(FALSE); break; }
  15. 15. 例外(プログラムミス) 可能な限りの終了処理をして プロセスを停止させる。 注)お客様との調整が必須。
  16. 16. 例外(プログラムミス) 堅牢性と正当性は相反する。
  17. 17. 例外(プログラムミス) size_t index = ・・・; std::vector<int> buf; ・・・ ASSERT_DEAD(index < buf.size()); buf[index] = 100;
  18. 18. 例外(プログラムミス) swtich(val) { ・・・ default: ASSERT_DEAD(FALSE); }
  19. 19. 例外(プログラムミス) そのまま動作させると・・・ ・永続データを壊すかも。 ・原因特定困難な不具合になる。 ・使われない復帰コードで コードが腐敗し、 さらなる不具合を招く。
  20. 20. 例外(プログラムミス) 潔く終了すると・・・。 ・変なデータができない。 ・不具合解析が楽。 ・コードはスッキリ。 ↓ 結果的にリリース品質が劇的に UP。
  21. 21. 例外(プログラムミス) あ、 「この辺は無理に終了しなくて も・・・」とかは無し。 その切り分けは難しく、 だんだん、生き恥をさらす方向に 行くので。
  22. 22.
  23. 23. テンプレート活用例 ①関数ポインタキャスト
  24. 24. ①関数ポインタキャスト FARPROC GetProcAddress( HMODULE hModule, LPCSTR lpProcName ); おなじみ、DLL関数取得。
  25. 25. ①関数ポインタキャスト 関数のロードが面倒・・・。 typedef void (__stdcall *FuncType)(int value); FuncType Func = NULL; Func = (Func)GetProcAddress(h, “Func”);
  26. 26. ①関数ポインタキャスト ちょっとしたユーティリティーを作っておく。 template<typename T> void GetEx(HMODULE hModule, LPCSTR name, T& func) { func = (T)GetProcAddress(h, name); } #define GETPROC(h, f) GetEx(h, #f, f)
  27. 27. ①関数ポインタキャスト スッキリ! void (__stdcall *Func)(int value); GETPROC(h, Func);
  28. 28. ①関数ポインタキャスト ついこないだも、 使っちゃいました。 →コードへ。 http://www.codeer.co.jp/tec hnical-notes/NativeAndNet
  29. 29. ②アロケータ記憶 DLLで、ランタイム異なるこ とありますよね・・・? (゚◇゚) 共通にすれば済む話・・・。
  30. 30. ②アロケータ記憶 そうすると、ヒープも 違うんですよね。 混ぜるな危険 Exe メモリ管理 dll メモリ管理
  31. 31. ②アロケータ記憶 でも、動的なコンテナ 使いたいんです。
  32. 32. ②アロケータ記憶 で、コンテナ作りました。 Σ⊂( ̄□ ̄~j
  33. 33. ②アロケータ記憶 template<typename T> class ArrayAllocator { public: T* (__stdcall *New)(unsigned int size); void (__stdcall *Delete)(T* ptr); ArrayAllocator() : New(NewCore),Delete(DeleteCore){}
  34. 34. private: static T* __stdcall NewCore(unsigned int size) { return new T[size]; } static void __stdcall DeleteCore(T* ptr) { if (ptr) { delete[] ptr; } } };
  35. 35. //配列 template<typename T> class Array { ArrayAllocator<T> _heap; ・・・ }; //文字列 class WString { Array<WCHAR> _core; ・・・ };
  36. 36. 入れ子もOK! struct Data { Array<int> ar; WString str; }; void _stdcall Func(Array<Data>& a) { //データを詰める }
  37. 37. ②アロケータ記憶 { Array<Data> a; Func(a); } 抜けたら、それぞれの メモリ管理のdeleteが 呼ばれる。 Void Func(Array<Data>& a) { a.resize(100); a[99].ar.resize(100); a[99].str = L“abc”;
  38. 38. ③AOPもどきでログを仕込む 関数の呼び出し順を ログ出力したことありますよね?
  39. 39. ③AOPもどきでログを仕込む 全部に、いちいち仕込むのは面倒! 横断的(AOP)に処理したい!
  40. 40. template <typename Ret, int fileNo, int lineNo> struct AOPLog { //DLL関数の型 typedef Ret (__stdcall *FuncType)(); //ログ static std::string& Log() { static std::string log; return log; } //DLL関数 static FuncType& Func() { static FuncType func; return func; } //ログ出力と呼び出し static Ret __stdcall Invoke() { Print(Log()); return Func(); } };
  41. 41. //戻り値voidで特殊化 template <int fileNo, int lineNo> struct AOPLog<void, fileNo, lineNo> { typedef void(__stdcall *FuncType)(); static std::string& Log() { static std::string log; return log; } static FuncType& Func() { static FuncType func; return func; } static void __stdcall Invoke() { Print(Log()); Func(); } };
  42. 42. //ログ入り関数ロード template<int fileNo, int lineNo, typename Ret> void MakeLog(HMODULE h, Ret (__stdcall *&func)(), LPCSTR name) { typedef AOPLog<Ret, fileNo, lineNo> T; if (s_logMode) { T::Func() = (T::FuncType)::GetProcAddress(h,name); T::Log() = funcName; func = T::Invoke; } else { func = (T::FuncType)::GetProcAddress(h,name); } }
  43. 43. //今のを引数が必要分繰り返す。 //BOOST_PPとか。 //でヘルパマクロ #define LOG_GETEX(fileNo, h, f) MakeLog<fileNo, __LINE__>(h, f, #f) //使うところは、すっきり。 void (__stdcall *Func)(); LOG_GETEX(0, h, Func);
  44. 44. そろそろ時間! ご清聴ありがとうございまし た。

×