C++ tips4 cv修飾編

2,838 views
2,774 views

Published on

主に cppll ML でご紹介してきた tips をC++の仕様をより掘り下げた形でまとめ直してみました。
今回はcv修飾にフォーカスした内容です。

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

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

No notes for slide

C++ tips4 cv修飾編

  1. 1. Boost.勉強会 #9 つくば ( 2012-05-26 )C++ TIPS 4 CV修飾編
  2. 2. 概要 主に cppll ML でご紹介してきた tips をC++ の仕様をより掘り下げた形でまとめ直し てみました。 今回はcv修飾にフォーカスした内容です。 C++ Tips Boost.勉強会 #9 つくば 2
  3. 3. 概要 cv修飾はC++のすばらしい機能のひとつで はあるのですが、細部は残念ところが 多々あり、注意が必要なのでしっかり復 習しておきましょう。 C++ Tips Boost.勉強会 #9 つくば 3
  4. 4. C++ TipsCV修飾
  5. 5. cv修飾ってなに? const 修飾と volatile 修飾を合わせて cv 修 飾( cv-qualifiers )と呼ばれます。  constexpr はcv 修飾とは関係ありません。ヤツ は 全然別物です。  cv 修飾は型とメンバー関数に対して付けるこ とができます。  元の型とは違う型と見なされ、オーバーロー ドの対象となります。 C++ Tips Boost.勉強会 #9 つくば 5
  6. 6. const const 修飾されたオブジェクトはJIS 的には 定値オブジェクトと呼ばれます。 const は厳密には二段階の意味があります。  一つ目は読み込み専用(readonly)であること。  二つ目は不変(immutable)であること。 C++ Tips Boost.勉強会 #9 つくば 6
  7. 7. const 読み込み専用(readonly)であること。  const なオブジェクトは書き換えられません。 C++ Tips Boost.勉強会 #9 つくば 7
  8. 8. const 不変(immutable)であること。  生成時から const として作成されたオブジェク トは変更できません。  この場合、コンパイラはコンパイル時にオブ ジェクトを作ってしまうことができます。ま た、そういうオブジェクトをconst_castなどで const外しを行い書き換えようとすると未定義 動作となります。 C++ Tips Boost.勉強会 #9 つくば 8
  9. 9. const const 参照あるいはconstなオブジェクトを 指し示すポインタは、その指し示すオブ ジェクトはreadonlyであるがimmutableで あるとは限りません。 C++ Tips Boost.勉強会 #9 つくば 9
  10. 10. const readonlyだがimmutableではない例: int a = 0; const int & b = a; printf("%dn", b); // 0 a = 1; printf("%dn", b); // 1 b = 2; // NG C++ Tips Boost.勉強会 #9 つくば 10
  11. 11. volatile volatile 修飾されたオブジェクトはJIS 的に は揮発性オブジェクトと呼ばれます。 最適化の抑止を意味します。  マルチスレッドプログラミングにおける諸問 題の回避を行ってくれるわけではありません。  メモリマップドI/Oなどを想定した機能であり、 実の所それ意外はほぼ要無しです。 C++ Tips Boost.勉強会 #9 つくば 11
  12. 12. 文法const int a = 0; // 前置int const b = 0; // 後置const volatile int e = 0; // const+volatilevolatile const int f = 0; // 順番は逆もOKで、意味は同じ。const int const c = 0; // 重複はNGconst int volatile d = 0; // 重複しない前置+後置はOKint * const g = 0; // ポインタに対する修飾は必ず後置int * const * h = 0; // ポインタに対する修飾は必ず後置const int * const * const i = 0; // ベース+各ポインタに対して C++ Tips Boost.勉強会 #9 つくば 12
  13. 13. 文法const int a = 0; // a は変更不可const int * b = &a; // *b は変更不可, b は変更可const int * const c = b; // c,*c は変更不可const int * const * const d = &c; // d,*d,**d は変更不可int e = 0; // e は変更可int * const f = &e; // f は変更不可, *f は変更可int * const * const g = &e; // g,*g は変更不可, **g は変更可int * const * h = &e; // *h は変更不可, h,**h は変更可 C++ Tips Boost.勉強会 #9 つくば 13
  14. 14. 文法// 引数に対するcv修飾に応じて// 適切にオーバーロードが機能します。void func(int & a);void func(int const & a);void func(int volatile & a);void func(int const volatile & a);void func(int && a); C++ Tips Boost.勉強会 #9 つくば 14
  15. 15. 文法// 参照やポインタでない場合は関数シグネチャ的には無視される。void func(int a);void func(int const a); // 宣言的には void func(X a); と等価。// 定義的には違いがある。void func(int a) { a = 0; // OK}void func(int const a) { a = 0; // constなので書き換えはNG} C++ Tips Boost.勉強会 #9 つくば 15
  16. 16. 文法class X { public: void func(); void func() const; void func() volatile; void func() const volatile; void func() &&; // 呼び出し時の this に対するcv修飾に応じて // 適切にオーバーロードが機能します。}; C++ Tips Boost.勉強会 #9 つくば 16
  17. 17. 文法class X { public: X(const int a) const; ~X() const; // コンストラクタとデストラクタに対するcv修飾はNG // ( コンストラクタの引数型に対するcv修飾はOK ) static void gunc() const; // 静的メンバー関数に対するcv修飾はNG}; C++ Tips Boost.勉強会 #9 つくば 17
  18. 18. 「よりcv修飾されている」 cv修飾に関する文脈上「よりcv修飾されて いる(more cv-qualified)」という表現が現れ ることがありますが、これは規格上次の 表のように定義されています。 C++ Tips Boost.勉強会 #9 つくば 18
  19. 19. 「よりcv修飾されている」 修飾の順序関係 cv修飾なし < const cv修飾なし < volatile cv修飾なし < const volatile const < const volatile volatile < const volatile C++ Tips Boost.勉強会 #9 つくば 19
  20. 20. const_cast cv修飾の状態のみを変換するキャストで す。 名前は const_cast ですが、 volatile につい ても修飾を付けたり外したりできます。 C++ Tips Boost.勉強会 #9 つくば 20
  21. 21. const_cast よりcv修飾されている型へは暗黙の型変 換が行われる為、明示的にキャストする 必要はありません。  これは安全なキャストについては暗黙の型変 換が行われるということであり、const_cast が必要になるという事は安全でないキャスト を行っているということであり、注意が必要 です。 C++ Tips Boost.勉強会 #9 つくば 21
  22. 22. const_castint a = 0;const int * b = &a;int * c = b; // NGint * d = const_cast<int *>(b); // const を一つ除去const int * * e = &d; // NG(後述)const int * * f = const_cast<const int * *>(&d); // const を一つ付加※const int * const * g = ...;int * * h = const_cast<int * *>(g); // const を一つ除去 C++ Tips Boost.勉強会 #9 つくば 22
  23. 23. 修飾の変換・互換ルール cv修飾の差異による型の変換・互換ルー ルは「よりcv修飾されている型へは暗黙 の型変換が行われる」ということさえ頭 に入れておけば後は概ね直感的に理解し やすいものなのですが、厳密にはやや変 則的で落とし穴が無くもないのでひとつ ひとつ見ていきましょう! C++ Tips Boost.勉強会 #9 つくば 23
  24. 24. 型の互換性:値型int a = 0;const int b = a; // コピーint c = b; // コピー...値型の場合、cv修飾の状況の関わらずコピーされる。※サンプルは代入ですが、関数の引数についてもルールは同じ。 C++ Tips Boost.勉強会 #9 つくば 24
  25. 25. 型の互換性:参照型int a = 0;const int & b = a; // よりcv修飾されている型へはOKint & c = b; // 逆方向はNGint & d = const_cast<int &>(b); // キャストすればOK C++ Tips Boost.勉強会 #9 つくば 25
  26. 26. 型の互換性:ポインター型int a = 0;const int * b = &a; // よりcv修飾されている型へはOKint * c = b; // 逆方向はNGint * d = const_cast<int *>(b); // キャストすればOKint * * e = &b; // NGint * * f = &d; // OKconst int * * g = &b; // OKconst int * * h = &d; // NG(後述)int * const * i = &b; // NGint * const * j = &d; // OKconst int * const * k = &b; // OKconst int * const * l = &d; // OK C++ Tips Boost.勉強会 #9 つくば 26
  27. 27. 直感的でない型の非互換性 なぜ const int * * 型の値に int * * 型の値を代入できないのか? int a = 0; int * b = &a; const int * * c = &b; // NG C++ Tips Boost.勉強会 #9 つくば 27
  28. 28. 直感的でない型の非互換性 ポインタ部分を除けば const int 型と int 型であり問題はない。 int a = 0; const int b = a; // OK(コピー) int c = b; // 逆方向もOK(コピー) C++ Tips Boost.勉強会 #9 つくば 28
  29. 29. 直感的でない型の非互換性 ポインタがあっても一段の const int * 型と int * 型であれば同じく問題は ない。 int a = 0; int * b = &a; const int * c = b; // OK int * d = c; // NG C++ Tips Boost.勉強会 #9 つくば 29
  30. 30. 直感的でない型の非互換性 しかし、 const int * * 型の値に int * * 型の値の代入はエラーになる。 int a = 0; int * b = &a; const int * * c = &b; // NG C++ Tips Boost.勉強会 #9 つくば 30
  31. 31. 直感的でない型の非互換性 もしエラーにならないとしたら?int a = 0;int * b = &a;const int * * c = &b; // 本当はエラー C++ Tips Boost.勉強会 #9 つくば 31
  32. 32. 直感的でない型の非互換性 もしエラーにならないとしたら?int a = 0;int * b = &a;const int * * c = &b; // 本当はエラーconst int d = 0;*c = &d;*b = 1; C++ Tips Boost.勉強会 #9 つくば 32
  33. 33. 直感的でない型の非互換性 もしエラーにならないとしたら?int a = 0;int * b = &a;const int * * c = &b; // 本当はエラーconst int d = 0;*c = &d; // *c も &d ともに const int * 型*b = 1; C++ Tips Boost.勉強会 #9 つくば 33
  34. 34. 直感的でない型の非互換性 もしエラーにならないとしたら?int a = 0;int * b = &a;const int * * c = &b; // 本当はエラーconst int d = 0;*c = &d; // *c も &d ともに const int * 型*b = 1; // おかしくね? *b が指してんの d だよ! C++ Tips Boost.勉強会 #9 つくば 34
  35. 35. 直感的でない型の非互換性 const int * * 型の値に int * * 型の 値の代入を許してしまうと結果として 明示的にキャストを使ってもいないの にconst外しを許してしまうことになっ てしまう!  とまぁ、そんなことにならないようにC++のコ ンパイラはエラーとして弾いてくれます。 C++ Tips Boost.勉強会 #9 つくば 35
  36. 36. 伝播性 ある変数をcv修飾するとその変数を参照 あるいはポインタ経由でアクセスする コードが全て同じくcv修飾されているこ とが要求されるようになります。 C++ Tips Boost.勉強会 #9 つくば 36
  37. 37. 伝播性 オブジェクトがcv修飾されると同様な効 果がそのデータメンバーとメンバー関数 にも及びます。データメンバーについて はさらにそれらのデータメンバーのデー タメンバーにも伝播が連鎖します。 C++ Tips Boost.勉強会 #9 つくば 37
  38. 38. 伝播性 最終的に末端部分で呼び出す外部から提供されるライブラリの関数(API)が適切にcv修飾されていない場合、必要に応じてconst_cast を使用してcv修飾を外すことになりますが、本当に外してもよいのか注意する必要があります。 C++ Tips Boost.勉強会 #9 つくば 38
  39. 39. mutable オブジェクトがconst修飾されている場合 でもデータメンバーにmutableを指定する ことでconst修飾を伝播させないこともで きます。  const修飾の伝播のみを無効化するもので、 mutableが指定されていてもvolatile修飾は伝播 します。 C++ Tips Boost.勉強会 #9 つくば 39
  40. 40. mutable class X { public: mutable int a; int b; X() { } }; const X x; x.a = 42; // mutableが効いているので代入可能 x.b = 42; // constなのでNG C++ Tips Boost.勉強会 #9 つくば 40
  41. 41. 伝播性の抜け・・・class X { const X x; public: //x.a = 42; これはさすがにNG int a; printf("%drn", x.a); // 0 int * b; *x.b = 1; // これはまだしも・・・ int & c; printf("%drn", x.a); // 1 X() :a(0), b(&a), c(a) { } x.c = 2; // しれっと代入可能・・・}; printf("%drn", x.a); // 2 C++ Tips Boost.勉強会 #9 つくば 41
  42. 42. 伝播性の抜け・・・ ほかにもコンストラクタおよびデストラ クタにはcv修飾がかからない為、コンス トラクタおよびデストラクタ内では本来 *this がconstな状態であってもcv修飾がか かっていないものとして動作します。 const修飾されているオブジェクトであっ ても delete で破棄できちゃったり・・・ C++ Tips Boost.勉強会 #9 つくば 42
  43. 43. 伝播性の抜け・・・class X { const X x; public: int value; const X * y = new X(); X() { delete y; value = 0; func(); } ~X() { value = 42; func(); } void func();}; C++ Tips Boost.勉強会 #9 つくば 43
  44. 44. 一時オブジェクトの延命 const且つ参照で受け取ることで一時オブ ジェクトをその受け取った側の変数と同 じスコープで延命できます。std::string func();std::string name1 = func(); // コピーconst std::string name2 = func(); // コピーconst std::string & name3 = func(); // 一時オブジェクトの延命std::string & name4 = func(); // NG C++ Tips Boost.勉強会 #9 つくば 44
  45. 45. volatileメンバー関数でロック ちょっとトリッキーなvolatile修飾の使い 方として、スレッド間で共有して使われ ることがあるオブジェクトをvolatile修飾 によってマークし、そのメンバー関数が 呼び出される際にvolatile修飾されている 場合にのみロックを行う手法があります。 C++ Tips Boost.勉強会 #9 つくば 45
  46. 46. volatileメンバー関数でロックclass X { public: int func() { ... } int func() volatile { return auto_lock(), const_cast<X *>(this)->func(); }};X a;a.func(); // スレッド間共有しないインスタンスではロックせずに処理volatile X b;b.func(); //スレッド間共有するインスタンスではロックして処理 C++ Tips Boost.勉強会 #9 つくば 46
  47. 47. C++ Tips質疑応答
  48. 48. C++ Tipsご清聴ありがとうございました。

×