世の中には藻のようなライトC++書き向けの資料が不足しているので,
大学院での普段使い(どんな普段だよ)用途で収集したものをまとめてみました.
間違ったことを色々書いてそうなので, 見つけたら直します.
はじめに
エディタの設定で*.cpp *.hのタブ幅を2(スペース2こ)にして縮小を図ります.
長ったらしい記述が増えるので, タブ幅2が読みやすいです(自分は)
ドキュメントを読む
- C++プログラミングガイド
モダン C++ プログラミング - 日本語公開記事 - サイボウズエンジニアのWIKI
- STLのドキュメント
cplusplus.com - The C++ Resources Network
C++ reference - cppreference.com
clangを使う
Clang - Wikipedia
gccよりもclangの方がC++ 規格に準拠していると言われています.
warningが増えるかもしれませんが, デバッグメッセージが親切なのでg++のメッセージがイミフなときに
clang++でコンパイルすると意味がわかって解決することがあります.
標準ライブラリを使う
∧∧∧∧∧∧∧∧∧
< STL!STL!STL!STL! >
∨∨∨∨∨∨∨∨∨
_ _
`/っ) /っ)
/ / ∧_∧ / / ∧_∧
\\( )\\( )
便利なSTLコンテナが用意されているので活用します.
hashが見当たりませんが, unorderd_mapが一応それに相当するようです.
http://www.cplusplus.com/reference/stl/
sort, find, for_each, findなどやりたいことは大体algorithmにある気がします.
#include <algorithm>
http://www.cplusplus.com/reference/algorithm/
たまにどっちにあるのか混乱しますが,
accumulate, partial_sumとかはnumericにあります
#include <numeric>
http://www.cplusplus.com/reference/numeric/
iostream,fstreamやstringstreamなど,ほげほげstream群も便利
int toInt(string s) { int r = 0; istringstream ss(s); ss >> r; return r; } string toStr(int n) { ostringstream ss; ss << n; return ss.str(); }
参照は便利
余計な一時オブジェクトを作るとメモリが無駄なので, なるべく参照渡しします.
void hogehoge(const std::vector<int>& vec) { std::cout << vec.size() << std::endl; // 実体のように扱えるが, 参照 }
Cだと class* obj とかポインタ受け取ってobj->propのようにアクセスしたり,
実体(コピー)を受けてobj.propのようにアクセスしたりでしたが, &参照が出来るようになって扱いやすくなりました. データを読み出し専用にしたい場合は, const宣言を忘れずに.
constを使う
わたしはかつてconstを全く活用していなく, 「漢のC++」というお言葉を頂戴したことがあります. *2
class GeodesicDome { private: const double radius; const int split_depth; public: std::vector<double> vertices; public: GeodesicDome(double radius, int split_depth) : radius(radius), split_depth(split_depth) {}; void createFromIcosaHedron(); void render() const; void dumpStatus() const; void output(const std::string& fname) const; };
変更したくないオブジェクトにはconstを付加し, インスタンス変数を変更しないメソッド宣言末尾にもconstを付加します. こうすると違反をした時にコンパイラが怒ってくれます.
constなポインタは記述が特殊なので注意が必要です.
残念だったなそのconstは外せる
constつければ安心・安全!!! はい, const_castでconstを取ることができます.
使うとイケナイことに手を染めている気分になれます.
char* s = "hogehoge"; int size = strlen(const_cast<const char *> (s); // strlenはsを変更しないので, 信用してcast
inline展開
inline宣言すると呼び出し元に展開されるので, 関数呼び出し時のオーバーヘッドを抑えることができます. 短くて何度も呼び出される関数はinline宣言にすると良い.
inline double hoge() { //なんかシンプルな処理 return xxx; }
コンパイラの最適化オプションについては
http://www.cqpub.co.jp/interface/column/freesoft/2002/200208/08-4.htm
展開すればするほど実行ファイルのサイズは大きくなり, コンパイルも遅くなるので注意します.
C++11の機能を使う
お使いのコンパイラは最新ですか?
C++11 - Wikipedia
$ g++ -std=c++11 $ clang++ -std=c++11
でコンパイルできます. 全部は全く把握してないので使いやすいものを列挙
auto
型推論ができるようになりました.
auto x = 42; // int auto y = 3.14; //float std::vector<int>iterator it = v.begin() // C++03 auto it = v.begin() // C++11
もう長ったらしいイテレータを記述しなくていいんですね先生!!!!!
やさしいfor
for (const auto& v: vec) { std::cout << v << std::endl; } for (const int x: { 1,2,3,4,5,6 }) std::cout << x << std::endl;
なぜいままでできなかったのか
参照&無しで受けると要素のコピーに(なったはず)
initializer list
要素の初期化がとても楽になりました.
std::vector<int> v0 = { 1,0,0 }; std::vector<int> v1 = { 1,0,0 }; std::vector<int> v2 = { 1,0,0 }; std::vector<std::vector<int>> v3 = { v1,v2,v3 }; std::vector<std::vector<int>> v4 = { {1,2,3}, {1,2}, {1} };
コンストラクタにも.
return std::vector<int>({1,2,3});
array
固定長配列が仲間入りしました.
使ってないけど,beginやendが使えるようになって, 生ポインタを触らなくてよくなった?
int* array = new int[5]; // 今までの std::array<int,5> = {1,2,3,4,5}; // 固定長配列
nullptr
C | C++ | |
NULL | (void*)0 | 0 |
CではNULLはvoid*でしたが, C++ではマクロで0になってるので謎挙動の原因になります.
関数オーバーロードで引数が異なるものがあるとき
void hogehoge(char* foo, int bar); void hogehoge(char* foo, void* bar);
第2引数でNULLをえいやと渡すと, intと解釈されてvoid hogehoge(char* foo, int bar);
の方が呼び出されてしまうので,
hogehoge(_foo, (void*)NULL);
とかvoid*キャストして頑張ってましたが, nullptrを渡せばよくなりました.
NULLはマクロで定義された0ですが, nullptrはぬるぽであることをコンパイラに教えることができます.
static_assert
cassertのコンパイル時評価版, static_assert
第2引数で文字列をとれるので, &&しなくてよくなった
assert(a==b && "[ERROR] a is not equal to b"); // 実行時 static_assert(a==b, "[ERROR] a is not equal to b"); //コンパイル時
暗黙的コピーコンストラクタの禁止
private宣言するとか頑張らなくても, deleteを指定すればコピーコンストラクタの使用を禁止できるようになりました.
class NoCopy { NoCopy(const NoCopy&) = delete; NoCopy& operator=(const NoCopy&) = delete; }
ラムダ
ラムダ関数が定義できるようになりました.
[](int x, int y) -> int { int z = x + y; return z + x; } [](int x, int y) { int z = x + y; return z + x; } // return val; の場合は戻り値型を省略できる
wikiによると[]内は
[] //ラムダ関数外のどの変数も使うことができない。 [x, &y] //xはコピーされる。yは参照渡しされる。 [&] //すべての外部変数は、もし使われれば暗黙的に参照渡しされる。 [=] //すべての外部変数は、もし使われれば暗黙的にコピーされる。 [&, x] //xは明示的にコピーされる。その他の変数は参照渡しされる。 [=, &z] //zは明示的に参照渡しされる。その他の変数はコピーされる。
のように扱えるようだ.
今まで外部関数を宣言していたのが, スマートに書けるように.
これでPerlとかでいうmapとかgrepも書きやすくなるんですかね.
#!/usr/bin/perl my $prices = [ 98, 4980, 12500 ]; my $pay = [ map { $_ * 1.08 } @$prices ]; #=> [105.84,5378.4,13500] my $found = [ grep { $_ > 1000 } @$prices ]; #=> [4980,12500]
mapはこんな感じか
// map func const double scale = 1.08; std::transform(v.begin(), v.end(), result.begin(), [scale](int x) -> double {return x*scale });
全然使いこなしてないので, 色んなユースケースを読んでみたい
本の虫: lambda 完全解説
boostを使う
Boost のプログラムソースは初心者にはとても読めるものではなく、またテンプレートを駆使するためコンパイル速度が非常に遅いです。
特に有用な機能は C++11 に取り込まれていますので、Boost を使うことはお勧めしません。
モダン C++ プログラミング - 日本語公開記事 - サイボウズエンジニアのWIKI
boostにあったような機能がC++11に組み込まれて標準化され...というのが結構あるようです.
C++11とBoostの対応付け - boostjp
Boost のプログラムソースは初心者にはとても読めるものではなく、
はい, とても読み辛いです.
boost_program_optins, boost_regex ぐらいしか使ったことないです(C++11のstd::regexの挙動が謎かったので)
splitはいつも自作で悲しいのだが, STLで何故かみあたらない...(実はあるのか・・?)
boostにはstring_algorithmが一応ある
http://www.boost.org/doc/libs/1_56_0/doc/html/string_algo.html
boostないと何もできなくなった
用法・容量に注意しましょう
ふええ...コンパイルが遅いよぉ...
なんでもboostのせいにするのはよくない
C++はなるべく書かない
最後に何いってんだよという感じですが, 研究ではC++はなるべく書かないようにしています.
勿論どうしてもC++でないと実装できない箇所はC++で作ります.
ただ, LLで書いた方が遥かにコストが低いパーツが多いので, C++で作る部分はコマンドラインオプションを受け取ってデータシートを吐く機能にとどめて, LLでラップして回したりしています.
リファレンス(vim用)
おお, こんな便利なものが...知らなかった
rhysd/unite-n3337 · GitHub
あっ
スマートポインタのこととか全然書いてない.....................................