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

More Related Content

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