プログラミング
C

概要

  • C++とSTLの細かい書き方

下位ページ

目次

C/C++の発達段階

  • C言語にはいくつかのレベルがある
段階許される開発習得すべき技術
入出力がきちんと動いているかも確認しない
入出力がきちんと動くことを1回確認する
メモリバイオレーションしない+未初期化変数を使わない共同開発で必須valgrind, cppcheck, コーディングルール.-O0でメモリクリーンを保証できないなら,-O3する資格はない.
変数名をきちんとつける共同開発で必須コーディングルール
アサートを入れるコーディングルール
try-catchする
コメントを適切につける(意味のないのはNo)共同開発で必須コーディングルール
入出力がきちんと動くことをスクリプトで自動確認する=擬似テスト駆動共同開発と大規模開発で必須問題が起きた時にテストを追加していく+サンプルと同様の役割を果たす
メモリリークしない組み込み・OS・サーバアプリケーション
網羅的な入出力できちんと動くことをスクリプトで自動確認テスト駆動=基本的には費用対効果で,網羅するかが決まる.UIとか無理なのもある
変数名,コメント以外のドキュメンテーション外部ライブラリで必須
セキュアプログラミング外部ライブラリで必須fortify, コーディングルール
  • 再利用性が死んでると,ファイルごとコピーみたくなって,メンテナンス不能なので,マジそれだけはやめて
  • 組織の習熟も必要
    • C++は能力のある人じゃないと書けない,だけではなく,能力のある組織でないと書けないが,C++を書いていいくらいの組織の能力とはなにか.
    • その時代ごとにルールは違う.オブジェクト志向が出ていなかったころのルールと今のルールは違う.
    • もちろん言語ごとにもルールは違う(C++じゃないとvalgrindとか言う必要ないし).
    • コーディングルール,Assert, テスト,valgrind, gdbなどいろいろありすぎるが,全部まさかやっていないよね.

Tips

bit演算

  • there exists m in N n = 2^mの判定。
    • n & (n-1)
    • long long n;
  • count trailing zeros
    • unsigned int n;
  • __builtin_ctz(n) = k * 2^m, k and 2 are coprimeなるm
    • __builtin_ctz(n)
    • __builtin_ctz(n) = LSB(n)
  • count leading zeros
    • __builtin_clz(n)
    • unsigned int n;
    • sizeof(n) – __builtin_clz(n) = argmin x < 2^i
  • n bitの補数表現a<-->int b
    • a = (b+1<<(n-1))%(1<<(n-1));
    • a = (b+1<<(n-1))&( (1<<(n-1))-1);
    • b = (a-1<<(n-1))%(1<<(n-1));

STL

vector

strstream

  • ss.str()は終端文字std::endsを自動挿入しない
       int code = 1000;
       std::strstream ss;
       ss << code << std::ends;

量化関数

文法

pure virtual

  • 純粋仮想にはvirtual = 0としなければならない。
  • それを引く仮想にも、virtualとしなければならない。

ゲッタ・セッタの生成プログラム

  • これに"int test"などを入力すると,ゲッタとセッタを出力してくれる
    awk '{printf("%s get%s(void){return %s;}\nvoid set%s(%s %s){%s = %s;}\n", $1, toupper(substr($2, 1, 1)) substr($2, 2), $2, toupper(substr($2, 1, 1)) substr($2, 2), $1, $2, $2 "_", $2);}'
  • 本当はvim scriptでやりたいのだが…

newと実体の動作の違い

  • 完全にコピーコンストラクタがおかしい以外考えられない。
    • new delete newで正常動作して、実体定義、実体代入で正常動作しない

親のコンストラクタを呼ぶ

decisionCross::decisionCross(StockDayStream* stock, int s, int m, int a)
    : decision(stock), _s(s), _m(m), _a(a)
{
}

sstreamとstrstream

  • str()が,sstreamはstd::string型を出力し,strstreamはchar*を出力する
  • strstreamはstd::endsを最後に入れる必要があるが,sstreamは入れてはならない.

coutに表示させる

#include <iostream> 

class HoldingStock {
public:
    int m_code;
    std::ostream& operator()(std::ostream& ros) {
        ros << m_code << " " << m_code << " " << m_sl << " " << m_tp;
        return ros;  
    }                 
};

isnanがあいまい

  • std::isnanとすれば解決

fstreamのパターン

 std::ifstream fin(args_csv);
 std::string line;
 while (std::getline(fin, line)) {
   std::string token;
   std::istringstream stream(line);
   while (std::getline(stream, token, ',')) {
     std::cout << '[' << token << ']' << std::endl;
   }
 }

知識

  • 文法とコーディングルールを分離すべきかも
  • 文法
知識名サンプル備考
親クラスがテンプレートクラスである場合、そのメソッドを呼ぶときにはthis->を明示http://d.hatena.ne.jp/tkng/20110419/1303176182
using namespace Namespace;はclassの中に書けない.
using Namespace::Classname;ではClassnameでアクセスできない.
using RoboLink? = ::Link;はclass public: の中になら突っ込める
constメソッドは,constメソッドを持つクラスのメンバ変数を変更しない形式的には,「constメンバ関数内から見た,メンバ変数は実体の場合&aがconst T*型となり,ポインタの場合aがT* const型となる.」と考えるとよい.例えば class hoge {int a; int* getA const { return &a; } };は,constメンバ関数内では&aがconst int*型なのに,返り値がint*なのでアウト,とか.(constメソッドは,constメソッドを持つクラスのメンバ変数を変更しない.クラスが有するHoge型メンバ変数aに対しては,aの中身の無変更を保証するために&aがconst T*型となる.一方,constメソッドを持つクラスが有するHoge*型メンバ変数aPtrに対しては,aPtr自体の無変更を保証する一方,aPtrの中身が変わるどうかは知ったことではないので,int* const a;とポインタ自体の変更を認めなくする.)
「constメンバ関数では、暗黙的に渡されるthisポインタがconstで修飾される」が最も基本的ISO/IEC 14882:2003, 9.3.2 The this pointer[class.this]
静的メンバ関数で,staticを付けるのは定義のみで,実装には付けてはならない
引数1コのみ持つコンストラクタは,暗黙のうちにコピーコンストラクタも定義Hoge(int hoge) { this->hoge = hoge; }はHoge hoge = 10;
引数1コの暗黙のコピーコンストラクタはexplicitで抑制できる
range based forを使っても良いfor(auto& x : v) { x *= 2; } C++17の話も http://qiita.com/rinse_/items/cdfce8aa6a685a8ebe0c http://imoz.jp/note/cpp11.html http://dtyazsk.blog.shinobi.jp/c--/c--11%E8%B6%85%E5%85%A5%E9%96%80 http://minus9d.hatenablog.com/entry/20130815/1376557665
namespaceのエイリアスをすると長い名前を短縮できるnamespace shortname = veryverylongnamespace;namespace netque = torutk::network::que;
namespaceの完全記述using std::endl; using std::cout; using std::cerr;はよく使う
ヘッダファイル中にusingディレクティブを使用するのは禁止
名前空間を複数の場所で定義しても、それらは同一
using宣言は,「それが書かれたスコープに」そのシンボルを追加する.名前空間そのものを取り込むわけではなくあくまでシンボルを取り込む
グローバル名前空間は、namespaceのブロックに囲まれていない場所で,::でアクセスchar path[::FILE_PATH_MAX];
クラス内に効果を持つusingは実はできないやりたいならnamespace E { using namespace std; /*OK*/ class Hoge { public: string s;};} http://blog.wizaman.net/archives/542
Cのconst int* const a;とは,前のconstは中身が変わらないという意味,後のconstはポインタ自体が変わらない前のconstは int const * const としても良い
静的変数・メソッドはアクセス制限のあるグローバル静的メンバ変数はオブジェクトに属するメンバ変数ではなく、クラスに属するメンバ変数です。アクセス制限が設定されていることを除けば、グローバル変数と同じ
  • コーディングルール
    知識名サンプル備考
    vector<bool>は使ってはならないhttp://d.hatena.ne.jp/aki-yam/20120307/1331117485
    hppもcppもnamespaceで囲うcppはusing namespace Namespace;でもできてしまうが,非常に不自然な上,明示的でないので,きちんと囲うこと.
    C++ではtypedefの代わりにusingを使う可読性が高く,テンプレートをtypedefできる.http://notmoon.hateblo.jp/entry/2015/05/13/151939 http://cpplover.blogspot.jp/2009/05/ctypedefaliasdeclaration.html http://qiita.com/Linda_pp/items/44a67c64c14cba00eef1
    C++はキャスト演算子を使ってのセマンティクスを明示すべきCのキャストは危険なのとセマンティクスが多義的なので良くない.static_castはいつものキャスト.const_castはconstとvalatileを除去するキャスト.reinterpret_castは基本非推奨.void*, int*への変換でWinAPI32とかで使う.dynamic_castは基本非推奨(継承関係をチェック。キャストできればキャストしてキャスト後の値, キャストできなければfalse.この処理にはポリモフィズムを使用すべき.従来のC風のキャストを使用したコードを安全に置き換える用途以外には使用すべきではありません) http://www.s34.co.jp/cpptechdoc/article/newcast/ http://d.hatena.ne.jp/tmatsuu/20090717/1247835994 http://www.geocities.jp/bleis_tift/cpp/newcast.html
    |C++では,Cのポインタのセマンティクスがシンタックスに対しことて多義的なので,スマートポインタ群を使うべき||安全性と開発速度の向上が見込めるだけでなく、プログラマの意図に合わせて「ポインタ」を記述し分けることができる.基本的には全部shared pointerで,外に出すときはweakにして責任がないことを明示し,クラス内やメソッド内の限られたスコープの場合はuniqueにする.uniqueだったものを外に出したくなる場合は当然ある.そういう時にはuniqueのポインタをsharedに書き換える.速度は?スマートポインタのいいサンプル集http://program.station.ez-net.jp/special/handbook/cpp/syntax/smart-pointer.asp http://qiita.com/hmito/items/db3b14917120b285112f, make_sharedを使うと良い, スマートポインタとデザインパターンの連携 unique_ptrの使い方実例|
    バージョン管理をnamespaceで実現可能ライブラリ側のコードnamespace XXLib {namespace V1 {バージョン1の機能} namespace V2 {バージョン2の機能} } ライブラリ使用者側のコードnamespace Library = XXLib::V2; Library::func(); // バージョン2の func() を呼び出す
    using namespaceは安易に使わない.特にusing namespace std;std空間の全ての変数を把握したり、拡張を予期するのは無茶
    C++ではcstdioのようにすることによって名前空間に包んだ安全な関数を呼び出せる
    C++では,メンバ関数の初期化をhppで行うべき全てのメンバ変数が少なくとも未初期化でないことが保証できるので嬉しい.速度を超攻めるときはこの限りではない.http://qiita.com/YYSS_101/items/cbd06352e047116359ce
    Cの生ポインタは,誰が開放責任を持つかは自明ではないので,必ず開放責任をコメントを書く
    所有とは、リソースの所有者が(1)自身が所有しているリソースは所有者以外の者からは決して解放されないという権利と(2)自身が所有しているリソースを最後に解放するという義務を負うこと
    C++11の時点で生配列は非推奨一般的に静的配列にはstd::array、動的配列にはstd::vectorが使われています。
    ライブラリは,絶対分かるassertを吐いて死ぬ(Eigen型)か,return 1のエラーコードを返して死なないライブラリは絶対勝手に死んではならない
  • 雑学
知識名サンプル備考
C++はセマンティクスとシンタックス,から統一的に理解できるcastは同じシンタックスで複数のセマンティクスが可能だった.ムーブコンストラクタは,セマンティクスに対するシンタックスがなかった.スマートポインタも.
C++11普及していないのはRHELが悪いRHEL 6のGCCのバージョンは4.4である。これは。C++11をまともにサポートしていない。次のRHELのバージョンは7であるが、これにはGCC 4.8が入るものとn思われる。しかし、すでにGCCの安定版は4.9だ。GCC 4.8もC++11実装に不具合が色々あってあまりお勧めできない
スタティックおじさんhttp://itpro.nikkeibp.co.jp/atcl/watcher/14/334361/122100450/
mainの前に関数を呼ぶattribute constructorというものがあるhttp://0xcc.net/blog/archives/000091.html
例外起因のメモリリークRectangle* r(new Rectangle(p1, p2)); if (in_a_mess) throw Mess(); // 例外を投げてみる // ねぇ、例外が投げられたときの後始末は? delete r;
C++11を業務で使うことが許されない場合、Boostライブラリからスマートポインタが利用可能
デストラクタを前提としたC++ではそもそも特別な仕組みを使わないと循環参照の解決は出来ないスマートポインタでたまに「循環参照が~」とか言って文句つける人が居ますが、冷静に考えてみてください、循環参照を発生させた時点でデストラクタの安全な実行が出来ません(片方を先に破棄すると、もう片方のオブジェクトはダングリングポインタを持つことになる)。
g++ --verboseでIオプションの場所が全部出る

疑問と後でまとめる

  • externについて.メソッドでexternをつけるのは慣習でしかない?変数だったらもちろん意味があるんだけど.
  • ただデータ形式を変換するだけのクラス(実体がある必要が感じられないという意味)の実装方法ってどうすればいいんだろう?
  • GoFデザインパターンとはクラスのメソッドを使用するにはそのクラスのインスタンスを生成しなければなりません。しかし、共通ライブラリのように使用頻度の高いメソッドの場合、そのつどインスタンスを生成していては効率が悪いのためstaticメソッドにすることが多い
  • unitテストは全部のテストを統合した実行ファイルを作るべきなのか,一つ一つ実行ファイルを作るべきの?
  • 例えばC++0xマスターが書いたプログラムは共同開発の時にエデュケーションコストを要求することになるが,それは組織の責任であるべきなのか.

例外(try, catch, throw)を学びたい

http://wisdom.sakura.ne.jp/programming/cpp/cpp35.html http://ufcpp.net/study/csharp/misc_exception.html 「メソッドの定める結果を達成できないなら例外を投げる」という方針でOK 利用法上の例外: 利用者側が正しい使い方をしていれば回避できる例外→例外はキャッチしない.例外の発生しうるメソッド本体(Doer: do するもの)に対して、 事前チェック用のテストメソッド(Tester)を用意する方法のことを Tester-Doer パターンやTryParse?パターンを使うと呼びます。これを使う 発生は避けれないが、復帰可能な例外→対処可能なら catch して対処してしまう。対処できない(あるいは、対処をもっと上の階層にゆだねた方がいい)場合catch しない。あるいは、一度 catch して、いくつか必要な操作(中途半端な状態を残さないためにロールバックを行ったり、ログを記録したり)を行ってから例外を再度投げる。標準の例外とは違う処理が必要な場合にのみ、自前で例外クラスを作成する(??).例えば、FileNotFoundException? を catch せずにそのまま上位に流してもいい場面では、自作の例外でラップしたりはしない。 以下の例面白い.ExistsからReadでファイルが消えている可能性を例外で潰す try {

   if (!File.Exists(filename))
   {
       text = "デフォルトのテキスト";
   }
   else
   {
       text = File.ReadAllText(filename);
   }

} catch(FileNotFoundException?) {

   text = "ファイルがなくてもデフォルトのテキストがあれば OK";

} 対処のしようがない致命的な例外は,何もしない.

その他

  • Cの関数のデフォルト(hppにデフォルトを書くと怒られる) void func(double t0=NAN, double t1=NAN) {} http://www7b.biglobe.ne.jp/~robe/cpphtml/html01/cpp01065.html
  • 以下を右辺値参照で何とか実装できないか
    OK
      Vector3d minusg = -g;
      m_baselink->setVd(minusg);
    NG
      m_baselink->setVd(-g);

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS