Successfully reported this slideshow.
Your SlideShare is downloading. ×

よいコード、わるいコード

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Loading in …3
×

Check these out next

1 of 28 Ad

More Related Content

More from 京大 マイコンクラブ (20)

Recently uploaded (20)

Advertisement

よいコード、わるいコード

  1. 1. よいコード、わるいコード 京都大学理学部数学系4回生 KMC ID: hatsusato 2015/05/11
  2. 2. 2/28 自己紹介 ● hatsusato – 理学部数学系4回生 ● 最近は数学基礎論とか集合論とかやってる。 ● プログラミング言語を作りたい。 – 趣味 ● 作画アニメ – すきなもの ● C++ – きらいなもの ● C++
  3. 3. 3/28 よいコード わるいコード ● そんなの ひとの かって – ではない。 – 良いコード、悪いコードは存在する。
  4. 4. 4/28 よいコード わるいコード ● この講座では、良いコード、悪いコードの例(当社調べ) を挙げることで啓蒙しようと思います。 – サンプルコードには、良いコードを書くのが難しいと定評 のある[要出典]、C++を用います。 ● 僕がC++と言ったらそれはC++11以降のC++のことです。 – 他の言語ではあまり役に立たないアドバイスもあるか も。 ● 良いコード、悪いコードを知って、ライバルに差を つけろ!
  5. 5. 5/28 よいコード わるいコード ● ここでの良いコードとは、保守性の高いコードの ことを指すものとします。 – 機能の追加・修正を行い易く、バグが発生しにくい。
  6. 6. 6/28 目次 ● 一貫性 – 初期化 – オブジェクトの整合 ● 疎結合 – 間接メンバアクセス – 非メンバ関数 – const教 ● 例外安全 – No new, No delete
  7. 7. 7/28 一貫性 ● コードの一貫性を保つ – 何をしたいコードなのかを誰が読んでもわかるようにす る。 – コードの表記の一貫性を保つ ● コーディング規約とか。 – オブジェクト表現の一貫性を保つ ● オブジェクトのコード上の見た目と表現する実体とを一致させ る。
  8. 8. 8/28 初期化 ● まず初期化しろ – 未初期化オブジェクトはしばしば未定義動作を引き起こ し、デバッグを困難にする。
  9. 9. 9/28 初期化 ● まだパフォーマンスを気にするような時間じゃな い – 初期化をあとですることによるパフォーマンス向上<< <<越えられない壁<<<<デバッグの利便性 – パフォーマンスは、ベンチマークを取ってから検討する。 – プログラムの処理にかかる時間の80%は、コード全体の 20%の部分が占める。
  10. 10. 10/28 オブジェクトの整合 ● 悪い例 – Cでは文字列を格納する領域を表現するのに、先頭ポイ ンタと領域の長さとの2つで表現する。 – 2つは密接に関連するのに、別々に管理される。 整合性のないオブジェクトが簡単に出来てしまう! #include <cstdio> char* fgets(char* str, int count, FILE* stream);
  11. 11. 11/28 オブジェクトの整合 ● 良い例 – stringクラスは文字列の情報をまとめて管理する。 オブジェクトの整合性は常に保たれる! #include <string> istream& getline(istream& input,string& str);
  12. 12. 12/28 オブジェクトの整合 ● お互いに強く依存するオブジェクトはまとめて管 理する。 – 我々が通常構造体などを導入して行っていること。 ● 単にまとめるだけでなく、オブジェクト全体が常に有 効な状態になるようにする。 – stringの保持する文字数とsize()とは連動する。
  13. 13. 13/28 疎結合 ● 各コンポーネント間の依存度をできるだけ下げる – 問題を細かく分割して考えることができる。 – 変更のもたらす影響の範囲を把握しやすくなる。 – コンポーネントの再利用性が高まる。
  14. 14. 14/28 間接メンバアクセス ● 悪い例 – オブジェクトのメンバに直接アクセスしている。 メンバの名前との依存関係がオブジェクトの外にま で染み出してしまう! #include <utility> pair<int, int> pii; pii.first = 0; pii.second = 1;
  15. 15. 15/28 間接メンバアクセス ● 良い例 – オブジェクトのメンバに間接的にアクセスしている。 メンバへのアクセスが抽象化され、自由度が増加! #include <tuple> tuple<int, int> tii; get<0>(tii) = 0; get<1>(tii) = 1;
  16. 16. 16/28 間接メンバアクセス ● メンバ変数より関数の方が疎結合 – 関数でアクセスするようにしておけば、変数の名前や表 現方法を変更しても、ユーザコードに影響しないように できる。
  17. 17. 17/28 非メンバ関数 ● 悪い例 begin()やend()をメンバとしてもたないオブジェクト に対して適用できない! template <typename C, typename F> void foreach(C&& c, F&& f) { for (auto it = c.begin(); it != c.end(); ++it) { f(*it); } }
  18. 18. 18/28 非メンバ関数 ● 良い例 begin()やend()のオーバーロードを追加すること で、任意のオブジェクトに対して拡張できる! template <typename C, typename F> void foreach(C&& c, F&& f) { for (auto it = begin(c); it != end(c); ++it) { f(*it); } }
  19. 19. 19/28 非メンバ関数 ● メンバ関数より非メンバ関数の方が疎結合 – メンバ関数は対応するクラスとの依存関係がある。 – メンバ関数はthisポインタへのアクセス権を持つので、ク ラスメンバとの依存性も高い。
  20. 20. 20/28 const教 ● 悪い例 sを書き換えるつもりがないのに書き換わっている! int s[5] = {0, 1, 2, 3, 4}; int d[5] = {}; for (int i = 0; i < 5; ++i) { s[i] = d[i]; }
  21. 21. 21/28 const教 ● 良い例 constをつければオブジェクトの不変性を明示でき る! const int s[5] = {0, 1, 2, 3, 4}; int d[5] = {}; for (int i = 0; i < 5; ++i) { s[i] = d[i]; // compile error }
  22. 22. 22/28 const教 ● const教 is 何? – ローカル変数を含めたあらゆるオブジェクト・関数にでき るだけconst修飾を施す思想のこと。 – constを付けずに書けるところでも、できるだけconstを 使って書くようにする。 – const教らしいコードの例 ● constをつければ実際安心! const int n = [](){ int tmp = 0; cin >> tmp; return tmp; }();
  23. 23. 23/28 例外安全 ● C++は例外機構を持つ – 例外が発生すると、従来のC的なエラーハンドリングで は対処できない不整合が発生しうる。 – 例外が発生した時に、リソースリークやデータの不整合 が発生しない保証を例外安全という。 ● 例外安全は難しい – 難しいからと言って諦めては、良いコードは書けない。 ● 例外安全でないコードはその時点で潜在的なバグを持つ。 – 例外安全を意識する姿勢は大切。
  24. 24. 24/28 No new, No delete ● 悪い例 secondの確保に失敗した場合、firstがリークする! struct X { X() : first(new int(1)), second(new int(2)) {} ~X() { delete first; delete second; } int *first, *second; };
  25. 25. 25/28 No new, No delete ● 良い例 IntPtrがそれぞれのリソースを管理するのでリーク しない! struct IntPtr { IntPtr(int n) : ptr(new int(n)) {} ~IntPtr() { delete ptr; } int *ptr; }; struct X { X() : first(1), second(2) {} IntPtr first, second; };
  26. 26. 26/28 No new, No delete ● もっと良い例 newやdeleteは自分で書かない! template <typename T, typename... Args> unique_ptr<T> make_unique(Args&&... args) { return unique_ptr<T>( new T(forward<Args>(args)...)); } struct X { X() : first(make_unique<int>(1)), second(make_unique<int>(2)) {} unique_ptr<int> first, second; };
  27. 27. 27/28 No new, No delete ● 訓練されたC++erはdeleteを書かない – newもラップして使うので、直接書かない。 ● デストラクタは1つの仕事だけをする – デストラクタが複数の仕事をしている。 → 対応する複数の初期化が存在する。 → 複数の仕事は同時にはできない。 → 一部しか初期化が済んでない段階で例外が投げら れると不整合が発生する。 → 例外安全でない。
  28. 28. 28/28 まとめ ● 変更に耐えるコードを書くよう心がけよう! – キーワード:一貫性・疎結合 – 例外安全は難しいけど、少しずつ慣れていこう。 ● 良いコードは身を助く – 将来困らないように(困らせないように)、今のうちに注意 しておこう。

×