2016年02月06日

昔書いたコードはたいてい気に入らない

最近 我々の業界ではJavaScriptによるブラウザゲームに回帰しています
なぜかと言われると正直、Appleの規約がころころ変わる、基準がわからないので
リスク回避ですね

そんなわけで、高速なJavaScriptエンジンを作りたい!
ので asm.jsを出力することに
babel-plugin-asm-js を使えば babelからasm.jsにトランスコンパイル出来る
ので使ったら
あまり実用に耐えうるものではありませんでした
(すでに7ヶ月 コミットされていない。issueたまってる)

かといって asm.jsを手書きするのは ナンセンス



なので、emscriptenからasm.jsをはくと
C++にまた原点回帰してしまった


ので、過去に作ったOpenGLESのライブラリをみていたら
全てが自作なわけです
GIFの圧縮展開、アニメーションGIF、減色、jpeg展開(GPGPU)、通信、json、行列計算、クオータニオン・・・

行列ライブラリは 悩む所です
emscriptenでjavascript化すると 大きなライブラリを使うとその分ファイルサイズも大きくなって
大変なので
場合によっては自作ライブラリを使えないかとみたところ


今思えば設計ミスが多い!!

例えば operator+= の戻り値をvoidにしていたが、 vec2& にすると、演算子連結しやすくなるとか
operator+=、operator + ・・・・・ は、friendで実装すれば
色んな順番で処理できる

vec += 10;  
も処理可能にできるし
vec = 10 + vec2;
にも対応出来る

知識では知ってたけど手抜いてましたね


他にも 浮動小数の除算は時間がかかるので、
operator/(float f) 系は、 1/f を求めて乗算にするとか

結果、自分の中で色々な 設計思想が固まったので よかった。


で、行列計算ライブラリは色々と悩んだのね

ライセンスが最もゆるく、boostに入っている、速度も良いという  uBLASS
OpenGLとの親和性は抜群といわれる ライセンスもゆるい(MIT) GLM
そして昔から評判のいい ライセンスは中ぐらい(MPL2) eigen

今回はとくにソースコードいじるつもりもないので eigenにすることにしました

ライブラリも名前考えて 作り始めようかなー


でもその前に 仕事が・・・・







blogram投票ボタン
posted by ゆき at 12:57 | 東京 ☁ | Comment(0) | TrackBack(0) | C言語関連 | このブログの読者になる | 更新情報をチェックする

2015年11月20日

thread coroutineで、例外を転送する

boost.asio でコルーチン使ってて、他のコルーチンでおきた例外を外部から取れないか・・・
と思ったら
threadで使う 例外の転送が コルーチンでも使えたのでメモ。。。


通常 threadでは、子供の例外や他人の例外をcatchすることは出来ないが
例外を保存することにより、外部で例外を発生させることが可能

std::exception_ptr を使えばオッケー


http://qiita.com/YukiMiyatake/items/91d90d53d8e1e135da62
blogram投票ボタン
posted by ゆき at 06:37 | 東京 ☁ | Comment(0) | TrackBack(0) | C言語関連 | このブログの読者になる | 更新情報をチェックする

2015年11月19日

C++初心者にありがちな・・・

昔は C++はC言語を覚えたあとに
BetterCとして C++を覚え
オブジェクト指向で記述する

そういった人がほとんどだったと思います
なので C言語が基礎にある

ところが、最近は C++から入った人も増えてきました
C++流の上級言語。文字列は std::stringで、ポインタは極力つかわず参照で

あるいみ C++から入るほうが楽かもしれませんし
良いコードを書くと思います


ところが そんなC++から入った人が、初歩的なミスをしていました



struct hoge{
char name[8];
}

std::string str;
str = hoge.name;


だいたい上記のようなコードです。
構造体の場合は、終端にnullがついていないデータを扱う事も多いので
上記のコードは 終端nullがなければ、ゴミが入ります
ので


std::string str;
str.assign( hoge.name, 8);


と、MAX文字数を指定すべきですね。

null終端の保証がない場合は、全部sizeの指定が必要です
char * から作成する際は、基本的に size指定すべきですね
blogram投票ボタン
posted by ゆき at 20:51 | 東京 ☁ | Comment(0) | TrackBack(0) | C言語関連 | このブログの読者になる | 更新情報をチェックする

2015年10月07日

json11 int64_t

C++におけるC++ライブラリの選択肢は色々ある
前は picoJsonを愛用していて、今でも十分に 小さく使いやすい
ヘッダのみで利用できるので、場合によっては今でも使う

けど、json11が評判いいし使っています

実際に使いやすい

ところが json11は uint32、int64、uint64 等がない。
全部において int_value である
プロトタイプをみると intである

C++においては、整数型とビット数が、規格ではちゃんと決まっていない。
処理系やコンパイラでビット数が異なる

一般的な64bitマシンではおおよそ
int: 32bit
long: 32bit
long long: 64bit

である

つまりおおよその処理系では json11の int_value() では 符号あり32bit数しかとれない

そこで double_value() を使って取ると、ちゃんと調査してないけど
53bitまでは取れるはずなので
uint32は取れる

が、int64、uint64に関しては 53ビットしか取れないため、残りの11bit情報が取れない


とりあえず jsonデータを stringにし、内部でint64に変換するのが 楽な気がする

一般的に Javaでも jsonライブラリはライブラリ毎に その辺りも微妙に事情が違うので
今のところは stringで受け渡しすることにした

そのうち json11も uint32 int64 uint64対応入れたいけどね。。。


そして 文字列から int64_tに変換するには おそらく  std::atoll で良いと思う
ただし long long == int64  の処理系限定である

もし long long != int64 処理系だと・・・
この際のベストプラクティスは何なのか・・・

悩みは色々あるけど、64bit環境では おそらくこれで大丈夫かと

ちなみに uint64_tが欲しい時は std::uatoll が使える



blogram投票ボタン
posted by ゆき at 10:48 | 東京 ☁ | Comment(0) | TrackBack(0) | C言語関連 | このブログの読者になる | 更新情報をチェックする

2015年05月26日

ちょっと便利な enum class (scoped enum)

ちょっとしたコネタレベルだけど

C++11では enumのかわりに enum class あるいは enum struct
を使うと良いという話

地味に便利なんだよ。

例えば 今まで enumは、ネームスペースを持っていなかったので
他のシンボルと名前がかぶるので
namespaceを作ったり、プリフィックスつけたりして
シンボル名の衝突を避けていたのが
デフォルトで名前空間を持つので
シンボル名がかぶる事なく使える

他にも
enumの型サイズは実装依存だったので コンパイラによりサイズが変わる可能性があったが
enum classだと、int型であることが明記されました
その事により 定義でサイズがわかるので、前方宣言可能になります

デフォルトはintですが、整数型(char、short、int、long等)を継承する事で
他の型にする事も可能

また、安全に型変換をするために
std::underlying_type
で内部型にキャストできます





とりあえず C++11使うなら enumを全部 enum class に変更すべきです

blogram投票ボタン
posted by ゆき at 00:30 | 東京 ☀ | Comment(0) | TrackBack(0) | C言語関連 | このブログの読者になる | 更新情報をチェックする

2015年05月25日

配列の参照を返す関数

まー 基礎的な事なんだけど C言語の文法って不思議なんです。
主に関数ポインタ関連ですけど

関数プロトタイプは Cでは
int add( int x, int y );

ですよね。でもGoでは
func add(x int, y int) int

と、一般的に知られてる C言語の文法から大きくかえたのは
C言語の文法だと 色々と問題があるからなんですね
その辺は
http://meryngii.hatenablog.com/entry/20080923/1222154366
このあたりみると いいです。
複雑です・・・


で、配列の参照の前に intを返す関数は

int hoge();

で簡単ですね。
参照は
int & hoge();
int配列のポインタは
int *hoge();

何も問題ないですね。

では、int配列の参照を返す場合はどうですか?

int n[10];

int[10]& func(){
return n;
}


こんな風に書きたい? 残念ですが コンパイルエラーです

C言語の文法では下記が正しい


int n[10];

int (&func())[10]{
return n;
}



キモい! けど 文法ではこれが正しい。

そこで boost::add_reference を使うと それなりに見やすくなる



#include
int n[10];

boost::add_reference::type func(){
return n;
}


int[10] の参照型をboost::add_reference::type  と書ける
コード量は増えるけど、こっちの方がぱっと見で わかりやすいと思うので
オススメ
blogram投票ボタン
posted by ゆき at 23:54 | 東京 ☀ | Comment(0) | TrackBack(0) | C言語関連 | このブログの読者になる | 更新情報をチェックする

std::random 事始め

とある事情があり std::random を使うことに

libcのrandもあるんだけど、C++11には新しく乱数ライブラリが入りました

通常のrandは、線形合同法等の古いアルゴリズムを使っているため、乱数に偏りが出たり規則性が出る、循環が短い
等々問題点が多いので
ちょっと意識の高い人は メルセンヌツイスター法(MT法) を使ってたと思います
MT法は、乱数アルゴリズムの中でも、偏りが少なく計算も速く、非常に強力です

C++11では、MT法等が抽象化され標準で使えるようになりました
これは一様乱数を作成するものですが、他にも正規分布、ベルヌーイ分布、ポワソン分布等
色々な分布を作成する事が可能ですし
今まで (rand() % 6)+1 等と余りを使ったりして乱数を取得していたのが
乱数の範囲も指定できるようになります
(しかも 上記の場合においては rand()を使うより速くなる事が多い)

つまりは とっても強力

とりあえず、簡単に MT法で乱数を出すなら


#include

int main(){
std::mt19937 r(static_cast(time(nullptr)));
for (int i = 0; i < 10; ++i) {
std::cout << std::hex << r() << std::endl;
}
return(1);
}


std::mt19937 というのが乱数生成機で、乱数シードに timeを入れる
わかりやすいですね。


これで十分だと思うのですが、random_deviceやseed_seq を使う事で
より良い乱数を作れるらしい
(この辺の詳しい所は 数学得意な人に教えてもらいたい)
ので 定型文として
下記のようにすると より良い乱数が得られる



#include

int main(){

std::random_device rnd;

std::vector< std::uint_least32_t> v(10) ;
std::generate( v.begin(), v.end(), std::ref(rnd) ) ;
std::seed_seq q( v.begin(), v.end());
std::mt19937 mt{ q } ;

for (int i = 0; i < 10; ++i) {
std::cout << std::hex << mt() << std::endl;
}
return(1);
}


random_deviceというのが、素晴らしい乱数を作るらしいが、速度の関係か
これを毎回呼ぶのは好ましくないっぽく、シードとして使う

vectorを使い、乱数シードを複数持つ??
ちょっと 細かく追ってないので想定の範囲でゴメンナサイ。
今回は10個シードを持ちます
注目は std::ref() を使ってる所かな。
参照で渡さなければ
calling a private constructor of class
で コンパイルエラー。


2つ目の注目は mt19937の引数 seed_seqは rvalue不可能という事

// OK
std::seed_seq q( v.begin(), v.end());
std::mt19937 mt{ q } ;

// NG
std::mt19937 mt( std::seed_seq( v.begin(), v.end()) );



このへんは、理由を調べるのはコードを追っかけないとよくわからないので
定型文として 何も考えずに覚える事にします


これで 整数の乱数が作成出来たので さいころを実装するのに
(mt() % 6) +1
でも可能ですが、uniform_int_distribution を使うとより高速で便利に出来ます
さらに std::bind を使い、dice() という関数オブジェクトにしてしまいます


#include

int main(){

std::random_device rnd;

std::vector< std::uint_least32_t> v(10) ;
std::generate( v.begin(), v.end(), std::ref(rnd) ) ;
std::seed_seq q( v.begin(), v.end());
std::uniform_int_distribution dist( 1, 6 ) ;

auto dice=std::bind(std::uniform_int_distribution(1,6), std::mt19937{q});

for (int i = 0; i < 10; ++i) {
std::cout << dice() << std::endl;
}
return(1);
}



んー いんじゃないですかー!

タグ:C++11 C++
blogram投票ボタン
posted by ゆき at 15:43 | 東京 ☁ | Comment(0) | TrackBack(0) | C言語関連 | このブログの読者になる | 更新情報をチェックする

2015年05月22日

CLion

C++のコードを書く時、今までは専ら Windows+VisualStudioでした

Macになってから、エディタに困っていました
XCODEって 重いし使い勝手あまりよろしくないし、インデントが嫌い
やはり VisualStudioに慣れてる身としてはね・・・

という事で CLionを評価していました
C++の全てを理解している統合環境は存在しないとして
補完もかなりしてくれるし、特に問題はなく便利です

先月 正式版が出て、個人でも1万円ちょいかかるようになったけど
結局 99ドルで購入しました
別に Vimでコード書いてclang実行してもいいんだけど
一応デバッグ機能あるし・・・ 
それになにより C++業界を盛り上げるには お布施は必要

他に気になっていたエディタは VisualStudioCode
ついにMicrosoftから MacでもLinuxでも動くVisualStudioの発表!!
しかも無料

使ってみたら 動作は速いし、使いやすい。
今の所 ASP.netとnode.js しか対応してないみたいだけど
今後 C#やC++も対応するだろうから
楽しみ




あとは やる気を購入したら仕事できる〜 blogram投票ボタン
posted by ゆき at 12:50 | 東京 ☀ | Comment(0) | TrackBack(0) | C言語関連 | このブログの読者になる | 更新情報をチェックする

2015年05月20日

歌舞伎座.teck 8

http://kbkz.connpass.com/event/13905/

歌舞伎座.teck 8で発表してきました

そもそもの経緯は、C++勉強会に参加したかったけど定員オーバーで
発表者枠しかなかったので・・・

そして 発表内容を見ると
C++業界で有名な人、暗黒魔法使い、VM業界で有名な人等々・・・
発表内容もどうみても初心者内容がないし

ので、ガチ初心者発表は呼ばれてない。かといって暗黒コードを今から作れないので

C++17に採用されるんじゃないかといわれている、最も熱いであろう
BoostとCoroutineの発表を考えた

まーそんな経緯ですね。

Boostは初心者じゃないとか、Asioは難易度高いとか意見もあるだろうけど
これがC++17から 入る可能性が農耕なのですよ

実際Asioの難易度は高いです。。。。

ちょっと20分枠に内容を詰め込み過ぎ感はあったので
一度 Asioのみの資料も作りたいと思いました
Asioってけっこう複雑怪奇ですので それでも何回かぶんの資料になるかと・・

わたしは C言語は低レイヤー等多少詳しいですが
C++もオブジェクト指向までは多少やってますが
STLは遅そうでなるべく使ってなかったので
C++実は初心者なんですが

関数オブジェクトを使っているのは中級者 というおおざっぱな指数でいうと 中級者に先月なったのかな・・
Asioのおかげで・・
って感じです


暗黒魔術師の多い勉強会ですが
Expression Template は勉強しなきゃと思いました

とりま STLに入っているクラスは 一通り勉強しようと思いました。
月末は boost勉強会!


タグ:C++
blogram投票ボタン
posted by ゆき at 10:41 | 東京 ☁ | Comment(0) | TrackBack(0) | C言語関連 | このブログの読者になる | 更新情報をチェックする

2015年05月01日

最強英語勉強法!

最強の英語勉強法を考えた。
もちろん アメリカで仕事するのが一番だけど
とりあえず 日本で手軽に勉強するには

英語ネイティブのオープンソースプロジェクトのコントリビュータになる事!

プログラミングで使う英語が学べるし、コンピュータ言語はわかるんで、英語の読解も楽かもしれない
ついでに 技術力もあがり、仕事もくるかもしれない

とりあえず 仕事で使う英語が学べるというのは大きいので
得意なC++から2個出してみた

・Node Webkit
https://github.com/nwjs/nw.js
Chromiumにて Webアプリでネイティブに動作するもの
サーバ側のnode.jsとクライアントのJavaScriptを透過で使えるらしい
ChromiumにネイティブAPIを追加して作ってるようだ

・ Caffe
https://github.com/BVLC/caffe
C++のDeepLearningライブラリ
知り合いにDeepLearning先輩がいるので!


他にも 面白そうなプロジェクトがないか探す!

あと もう少しC++勉強して cppref.jp の作業も復活したい

そんな感じで がんばるよ〜 blogram投票ボタン
posted by ゆき at 00:01 | 東京 ☁ | Comment(0) | TrackBack(0) | C言語関連 | このブログの読者になる | 更新情報をチェックする

2015年04月21日

近況

最近の近況です

C++とJavaのゲームサーバの開発を一括で請け負っています
最初はお客さんより通信ライブラリを頂けるとの事で
Javaを1名、C++を私+2名程度で考えていましたが
お客さんのライブラリが、マルチスレッド型で速度が全然出ないのが予想できたので

boost.Asioを使い、非同期I/O で超高速サーバを作成する事にしました
ってことで +2名が 技術的に脱落し、C++は私一人で開発する事となります・・・

boost.Asioや 非同期I/O あるいはノンブロッキングI/O
に関しては色々と説明したい事がありますが、簡単に説明出来る内容ではないので・・

非同期I/O はシングルスレッドで非同期処理を行います
カーネル等で使われる DMAを想像すればわかりやすいかもしれません
転送命令を送り、転送完了時にコールバックが来ます
ゆえに、コードがコールバック地獄となり、可読性が悪く 見つけにくい不具合の温床になります

ので、よく future/promise 方式や coroutine等を使い、コールバックを直列処理のように扱うと便利です
そのあたりについて、プレゼン資料を作っています

2015/05/17 13:30 に
ニコニコ動画主催の、歌舞伎座.teck にて久々に登壇します
http://kbkz.connpass.com/event/13905/#feed

すでに参加人数は容量オーバーですが、ニコ生で放送されるので
色々と面白そうな内容が多いので是非観て下さい

「Boost.Asioで可読性を求めるのは間違っているだろうか」
というタイトルで発表します。
タグ:C++ asio boost
blogram投票ボタン
posted by ゆき at 17:39 | 東京 ☁ | Comment(2) | TrackBack(0) | C言語関連 | このブログの読者になる | 更新情報をチェックする

2015年02月15日

boost::asioは shared_ptrでセッション管理すると楽という話

http://qiita.com/YukiMiyatake/items/f4641c54151a18c362f9

boost::asio のサンプルの解析

要点を絞ると、boost::asioで非同期に通信をする場合に
オブジェクトの生成と破壊のタイミングが直感と反する

sessionを管理する場合に shared_ptrを使うと比較的簡単になるという例
ラムダのキャプチャに参照を保持するのは 思いつかなかった。



タグ:C++11 boost asio
blogram投票ボタン
posted by ゆき at 19:46 | 東京 ☀ | Comment(0) | TrackBack(0) | C言語関連 | このブログの読者になる | 更新情報をチェックする

2015年02月11日

C++でTCP/IP通信 part1 boost::asio

http://qiita.com/YukiMiyatake/items/456e95f7d2fa79e463db

boost::asio
けっこう使い方難しい。同期で使うのは簡単なんだけど
非同期(ノンブロッキング)で使うのは そこそこ難しそうなので
お勉強はじめました

いちおう Qiitaに毎週1個記事を書こうと思ってます。
今回は同期の使い方だけど、次回は Proactorモデルをやってみます

って ネットにも情報乗ってるけど、人に見てもらう事、人に説明する事で
自分の理解が足りてない部分が理解出来るので
恥ずかしながらも UPして マサカリ期待してます♪ blogram投票ボタン
posted by ゆき at 12:40 | 東京 ☀ | Comment(0) | TrackBack(0) | C言語関連 | このブログの読者になる | 更新情報をチェックする

2013年11月19日

コピーコンストラクタ&代入演算子&ムーブコンストラクタ&ムーブ代入演算子

C++って言語仕様が多くて大変なので
勉強&復習しながら メモ残します

ってことで、結構難しい コンストラクタちゃんです。
本当はコンストラクタだけで 5,6個はTipsあるのですが
とりま コンストラクタの種類

class Cがあった場合
C(); // デフォルトコンストラクタ
C( const C& rhs); // コピーコンストラクタ
C& operator=( const C& rhs); // 代入演算子

上記3つはコンパイラによって自動生成されます。が、メンバをそのままmemcpyするので
たとえばポインタを内部で持っている場合は、コピーしたClassも同じポインタを参照するので
コピー先がポインタ削除したらコピー元は落ちちゃいます。 ってので デフォルトコンストラクタには注意

C( C&& rhs); // ムーブコンストラクタ
C& operator=( C&& rhs); // ムーブ代入演算子

C++11で新しく出てきたやつですね。

そんなわけで、呼んでみるテスト




#include <iostream>
#include<vector>
#include <string>
using namespace std;


template<class T>
void print( const char* c, T& t )
{
cout << c << t.s << endl;
};

class C
{
private:
vector<int> n;
public:
string s;


C()
: n(1)
, s("DefaultConstuctor")
{
;
};

C( const C& rhs)
: s("CopyConstuctor")

{
n = rhs.n;
};

C( C&& rhs)
: s("MoveConstuctor")
{
n = move(rhs.n);
};

C& operator=( const C& rhs)
{
n = rhs.n;
s="CopyAssignmentOperator";
return *this;
};

C& operator=( C&& rhs)
{
n = move(rhs.n);
s="MoveAssignmentOperator";
return *this;
};
};

void main()
{
C c;
print( "C c:\t\t", c );

C c2(c);
print( "C c2(c):\t", c2 );

C c3 = c;
print( "C c3 = c:\t", c3 );

C c4;
c4 = c;
print( "c4 = c:\t\t", c4 );

C c5(move(c));
print( "C c5(move(c)):\t", c5 );

C c6 = move(c2);
print( "C c6=move(c2):\t", c6 );

C c7;
c6 = move(c3);
print( "c7 = move(c3):\t", c7 );
}


実行結果

C c: DefaultConstuctor
C c2(c): CopyConstuctor
C c3 = c: CopyConstuctor
c4 = c: CopyAssignmentOperator
C c5(move(c)): MoveConstuctor
C c6=move(c2): MoveConstuctor
c7 = move(c3): MoveAssignmentOperator


色々注目はあるんだけど

まず、コンストラクタ、代入演算子では privateメンバを参照できます! そういうものです。

そして注目は 
C c3 = c;
パッと見で直訳すると、 c3をデフォルトコンストラクタで生成し 代入演算子で cからコピー
ですが、 コピーコンストラクタにより cから生成する方が早いですよね 
ってことでコンパイラが気を利かせて = 使ってるけどコピーコンストラクタで実装してくれます。

ムーブは std::move 使ってください。で、これは 所有権を移動するのです。
たとえば上記ソースでは vector を ムーブ以外ではコピーしてますが
これがたとえば要素数が100万とかあった場合、 コピーにコストがかかるので
ムーブ(ポインターをすげ替える)のが std::moveです。
そして ムーブ元は ポインタがNULL になります
ので、
C d(move(c)); // cのデータの所有権をdへ譲渡した
この後 c.n をアクセスするとヌルポエラーになる

ってことで std::moveや そうですね explicitの話その他は別の時に。
blogram投票ボタン
posted by ゆき at 08:26 | 東京 ☀ | Comment(1) | TrackBack(0) | C言語関連 | このブログの読者になる | 更新情報をチェックする

2013年11月17日

範囲に基づくforループ (range-based) for

C++は古い言語ですが 拡張されどんどん近代化改装が行われています

C++03、C++11 ときて、もうすぐC++14がきます。
もちろん C++の後の数字は 西暦年ですね。
ってことで C++11は 2011年に決定された言語仕様ということになります

先ほどサンプル書いた中でとても便利なものが いっぱいあります
auto も便利なのですが とりあえず
範囲に基づくfor を見てみます


for (const auto& x : m) {
cout << "[" << x.first << "," << x.second << "], ";
}


さらっと書いたこの部分ですね

for文はCゲンガーなら
for(int i=0; i<10; i++)
のように覚えたと思います
for(ite it=x.begin(); it!=x.end(); it++)
STLなら上記のように書くでしょうか

あるいは std::for_each を使うかもしれませんが
それが
for (const auto& x : m)

これだけで終わります。なんと簡単なのでしょうか!
この表記を 範囲を基にしたfor (range-based for) と呼ばれてます。正式名称は知りませんが。
Java等と同じ表記なので説明は不要だとおもいますが
上記の mがコンテナで、xに iteratorが返ってきます
このfor文は、m.begin()からm.end()まで ループし、iteratorがxに入ってきます

一応 auto も説明しますが、これは コンパイル時の型推論です。
この場合xの型が mのイテレーターであることがコンパイル時にわかるので
こんな楽してOKです


で一応 std::for_eachと range-based for の比較

#include <iostream>
#include <map>
#include <algorithm>
using namespace std;


void disp( pair<const int,char>& p) {
cout << p.second << endl;
}

int main()
{
map<int,char> m;

m.insert(make_pair(1,'a'));
m.insert(make_pair(2,'b'));
m.insert(make_pair(3,'c'));


cout << "--- range-based for" << endl;
for(const auto&x: m){
cout << x.second << endl;
}

cout << "--- for_each" << endl;
for_each(m.begin(), m.end(), disp);

return(0);
}



#実行結果
--- range-based for
a
b
c
--- for_each
a
b
c


似たようなものですが、for_eachの方は 関数オブジェクト、あるいはラムダ式を使う必要があり
begin()やend() を明記する必要ありますが
range-based for の方は、完結にかけてると思います
タグ:C++11
blogram投票ボタン
posted by ゆき at 23:44 | 東京 ☀ | Comment(0) | TrackBack(0) | C言語関連 | このブログの読者になる | 更新情報をチェックする

unordered_map、unordered_multimap

ちょっとわけあって、C++のリファレンスなるものを 生意気にも書いている
そんなわけで、今まで適当に使ってきた STLの勉強にもなって ありがたい

C++11 になって、std::unordered_map、std::unordered_multimap というコンテナが増えた。
std::map 等は、キーの順番にデータが保存されますが(だいたい2分木で実装するようです)
std::unordered_map等は、順番が保障されません。
理由は hash値でやってるのですね。
もちろんメリットは検索速度です
std::map等では sizeが増えると 対数的に検索時間が増えますが
hash値を使っているので 基本的に 定数時間で操作できます

ってこれ、名前が変な名前になってるけど boost::hash_map です。
どうやら、ほかのライブラリとの名前の衝突を避けるために unordered_mapという変な名前になったそうです

ってことでサンプル

#include <iostream>
#include <map>
#include <unordered_map>

using namespace std;

template <class Map>
void print(const char* name, const Map& m)
{
cout << name << " : {";
for (const auto& x : m) {
cout << "[" << x.first << "," << x.second << "], ";
}
cout << "}" << std::endl;
}

int main()
{
map<int, char> m;
m.insert(std::make_pair(30,'a'));
m.insert(std::make_pair(10,'b'));
m.insert(std::make_pair(20,'c'));
m.insert(std::make_pair(40,'d'));
m.insert(std::make_pair(15,'e'));
m.insert(std::make_pair(4,'f'));

unordered_map<int, char> u;
u.insert(std::make_pair(30,'a'));
u.insert(std::make_pair(10,'b'));
u.insert(std::make_pair(20,'c'));
u.insert(std::make_pair(40,'d'));
u.insert(std::make_pair(15,'e'));
u.insert(std::make_pair(4,'f'));


print("m", m);
print("u", u);

}


#実行結果
m : {[4,f], [10,b], [15,e], [20,c], [30,a], [40,d], }
u : {[30,a], [10,b], [4,f], [20,c], [40,d], [15,e], }


std::mapの方は、Keyの値でちゃんとソートされてますが
std::unordered_mapの方は、よくわからない順列ですよね

hash関数は 実装依存なので、コンパイラによって結果が違う可能性があります
私の環境は VisualStudio2012です。
もちろん hash関数を自前で用意すれば、実装依存なくできます
タグ:C++11 STL
blogram投票ボタン
posted by ゆき at 23:13 | 東京 ☀ | Comment(0) | TrackBack(0) | C言語関連 | このブログの読者になる | 更新情報をチェックする

2013年11月15日

cpprefjp

C++ゲンガーの総本山 cpprefjp

C++標準化委員会で憧れの アキラさん主催する、C++のリファレンスサイトです
ちょっとご縁がありまして、こちらの作業を手伝うことにしましたが
プログラム以外の部分で色々とつまづいておりますw

もしかしたら、ここを見てcpprefjpのお手伝いをしたいという人がでた時のためのメモを少しずつ・・・

https://sites.google.com/site/cpprefjp/
ここが メインサイトです。googleサイトですね。
しかしこのページは andareというスクリプトで自動生成してるようです
ので、編集するのはここではありません。
GitHubの方で編集します


手順
https://github.com/cpprefjp/site
ここが、編集するリポジトリです。
Markdown形式でかきます。
andareで変換時の注意点もあるので後ほど追記・・・

https://github.com/cpprefjp/site/issues?state=open
ここがissueです
手伝いたい作業があれば とりあえず 「やります!」ってコメントすれば
アサインしてくれます

あとは、forkして、ブランチきって、完成したら pull requestすればよいようです

って まだよくわかってないので
追記します・・・




blogram投票ボタン
posted by ゆき at 05:04 | 東京 ☁ | Comment(0) | TrackBack(0) | C言語関連 | このブログの読者になる | 更新情報をチェックする

2013年11月02日

FFT 始めました! part.1

こんばんわ 自称スーパーハカーアイドル ちはやです

ここ数年風邪ひいてない、オレバカ確定wwwww
ってつぶやいて、まわりから
「ちはやさん頭いいよ!10まで数えられるもん!」
って 慰めてもらった翌日

100年に一度の風邪をひきやがりましたよ! こんちくしょ〜!

ってことで、今まで 部屋の中で、着る寝袋を着て 毛布にくるまって
妖怪寝袋星人になってましたよ

ってことで続き


この間の数式から(結局TeXよくわからんから Wikipedia画像w)

FFT(高速フーリエ変換)ですね!


畳み込み


このあたり、実はわたし 算数得意じゃないからよくわからないんですよね。
積分が面積で シグマが合計で まぁ そんなレベルなのであります
なので フーリエ変換を基本から勉強せななーって。


まずは 習うより慣れろ!ってことで 有名なFFTライブラリ FFTW 導入しようと思います

今回は このサイト
WindowsでFFTを使う
さんを パク いや 参考にさせてもらいます!


http://www.fftw.org/download.html
から。
とりあえず 今回はWindowsのDLLをダウンロードし
展開したディレクトリ上で、VisualStudioのコマンドライン立ち上げ
今回は32ビットアプリで勘弁して!

lib /machine:i386 /def:libfftw3-3.def
lib /machine:i386 /def:libfftw3f-3.def
lib /machine:i386 /def:libfftw3l-3.def

ってやると 3つのライブラリができる

libfftw3-3.lib (単精度用)
libfftw3f-3.lib (倍精度用)
libfftw3l-3.lib (ロング精度用)

たぶん今回は 単精度しか使わないだろうけどっ!

で、それらの入ってるディレクトリを VisualStudioのリンク、実行ファイルのディレクトリに追加


そして サンプルのFFTWを使ったプログラムを ほぼそのままぱくりで
コンソールアプリとして作ります。



#include
#include
#include
#include "fftw3.h"
#pragma comment(lib, "c:/lib/fftw3/libfftw3-3.lib")

#define SIZE 128
#define RANGE 10



int main()
{

int i;
fftw_plan plan;
fftw_complex *in_buf, *out_buf;

in_buf = (fftw_complex *)fftw_malloc(sizeof(fftw_complex)*SIZE);
out_buf = (fftw_complex *)fftw_malloc(sizeof(fftw_complex)*SIZE);

for(i = 0; i < SIZE; i++){
in_buf[i][0]=0.0;
in_buf[i][1]=0.0;
}

for(i = 0; i < RANGE; i++)
in_buf[i][0] = in_buf[SIZE - i - 1][0] = 1.0;

printf("#Input Function\n");
for (i = 0; i< SIZE; i++)
printf("%d %f %f\n", i, in_buf[i][0], in_buf[i][1]);
printf("\n\n");

plan = fftw_plan_dft_1d(SIZE, in_buf, out_buf, FFTW_FORWARD, FFTW_ESTIMATE);
fftw_execute(plan);


const float rsize = 1.0f/sqrt((float)SIZE);
printf("#FFT by fftw\n");
for (i = 0; i< SIZE; i++)
printf("%d %f %f\n", i, out_buf[i][0] * rsize, out_buf[i][1] * rsize );

getch();


return 0;
}




すると コマンドプロンプトにそれっぽい値が出るはず

とりあえず 今回はこれで満足して

つぎは また例のページぱくりで グラフ出力! blogram投票ボタン
posted by ゆき at 21:22 | 東京 ☁ | Comment(0) | TrackBack(0) | C言語関連 | このブログの読者になる | 更新情報をチェックする

2013年10月30日

VisualStudio2013 Boost1.54 インストール的な

ってことで とりあえず VisualStudio2013のExpressをインストールしました

このExpressってのは ただなんですよね。ほんとお得!
でも 少し前までは毎回ちゃんと買ってたんですよ
MSDN(年間20万でOSやDDKなども毎月送られてくる) も入ってたんですよ!
バカですね!

だから 最後に買ったVisualStudioがいつだろうね・・・2008だと思います
それ以来、Expressで満足してます。

ていうかほんとうは IntelCompilerスイート 欲しいんだけどね!


で VisualStudioは何も問題なく簡単にインスコできました


そしてBoostです。
http://www.boost.org/users/download/

から 安定板の1.54 落としてきます

ダメですね、C++標準化委員会とMicrosoftMVPを目指している IQ 1億と2000の ちはやさんが
開発中の1.55 を使わないなんて・・・

まぁ これには理由があるので 許してください


で Getting Started かなんかかいてるところから 英語をよみつつ Buildしますが
なんかうまくいかない
なんか 環境変数設定したのに コマンドプロンプトが反映しないぞ??
Windows8 に問題があるのか、VMWareに問題があるのか 使い方ミスってるのかわからないけど
手で環境変数 SETしたり 苦闘しましたが

https://sites.google.com/site/boostjp/howtobuild

日本語で丁寧に説明がある さすがBoostJP様!!

ってことで 彼らの努力に感謝して日本語つかいます

インストールディレクトリにいて
# bootstrap
# b2 install -j2 --prefix=hoge

おわりwww 簡単である
もちろん複数のコンパイラいれてたら それぞれ指定したり
特定のライブラリを無視したり有効にしたりとか オプションはありますが

でもね boostcpp.jamがみつからないって コンパイルできません

結論から言うと 英語のドキュメント参照
インストールディレクトリではなく
BOOST\tools\build\v2 で、コマンド実行しなきゃダメでした


たぶん無事インストールおわったので

明日から遊ぼう


そう、今は MBP上のWin8より。 blogram投票ボタン
posted by ゆき at 02:49 | 東京 ☁ | Comment(0) | TrackBack(0) | C言語関連 | このブログの読者になる | 更新情報をチェックする

2012年09月24日

C++の仮想関数の仕組み&静的に呼ぶ方法

C++における関数のオーバーライド、ポリモーフィズムは
知ってる人には常識だけど他のオブジェクト指向言語の人は悩む事が多い



baseクラスから subA subB クラスを派生させ
printメソッドをオーバーライドさせ
ポリモーフィズムで 実行させる例


class base
{
public:
void print()
{
printf( "base\n" );
}
};

class subA : public base
{
public:
void print()
{
printf( "subA\n" );
}
};

class subB : public base
{
public:
void print()
{
printf( "subB\n" );
}
};



base *cls[3];

cls[0] = new subA();
cls[1] = new subB();
cls[2] = new base();


for( int n=0; n<3; n++ )
{
cls[n]->print();
}


結果:
base
base
base


subA subBクラスで printをオーバーライドしたはずなのに
スーパークラスの printメソッドが呼ばれてしまう

アセンブラだと


mov eax,dword ptr [n]
mov ecx,dword ptr cls[eax*4]
call base::print (1C113Bh)


base::print を呼んでいるので 当然の動き。


問題は
base *cls[3];
C++では通常はメソッドをオーバーライドしても、呼び出したクラスのメソッドが呼ばれる

ポリモーフィズム的には

cls[0]->print();
は、subA のメソッドを呼んでほしい

そういう場合は メソッドに virtualをつける





class base
{
public:
virtual void print()
{
printf( "base\n" );
}
};

class subA : public base
{
public:
virtual void print()
{
printf( "subA\n" );
}
};

class subB : public base
{
public:
virtual void print()
{
printf( "subB\n" );
}
};



base *cls[3];

cls[0] = new subA();
cls[1] = new subB();
cls[2] = new base();


for( int n=0; n<3; n++ )
{
cls[n]->print();
}


結果:
subA
subB
base


これで正しく ポリモーフィズムが出来た。
なぜ スーパークラスのポインタ型なのに サブクラスのメソッドが呼べたかのからくりは
virtual method table(vtable)にある。

virtualで宣言するとそのメソッドは vtableが作られる
このvtableは virtualメソッドへの関数ポインタが入っていて
オーバーライドの際に、このvtableの値が サブクラスの関数ポインタへと置き換わる

その辺は 他のページみて下さい。
要は virtualでメソッドを宣言したら 関数アドレス直接ではなく、vtableを使った間接呼び出しになること
また vtableはnewした時に、サブクラスの関数アドレスが代入されること
ゆえに スーパークラスのポインタでcallしても サブクラスのメソッドが呼ばれる


アセンブラだとこう

cls[n]->print();
00E61712 mov edx,dword ptr [n]
00E61715 mov eax,dword ptr cls[edx*4]
00E61719 mov edx,dword ptr [ecx]
00E6171B mov esi,esp
00E6171D mov ecx,eax
00E6171F mov eax,dword ptr [edx]
00E61721 call eax


そして call eax の先(vtable)は

jmp subA::print (0BD19D0h)


vtableを使い 間接呼び出しを行っている




ここまでは C++使ってる人には常識だけど


この 間接呼び出しは遅い。
jmp命令が入るだけのようだが
コンパイラが静的に関数アドレスを解決出来ないため
コンパイラが最適化出来ないのが 痛い。


じゃあ どうやれば速くなるか・・・ という事ですが
まず 仮想関数を静的に呼ぶ方法から。
けっこう知らない人が多いので

色々と 表記ができます

まず先ほどの 愚直にCallする


cls[n]->print();
00E61712 mov edx,dword ptr [n]
00E61715 mov eax,dword ptr cls[edx*4]
00E61719 mov edx,dword ptr [ecx]
00E6171B mov esi,esp
00E6171D mov ecx,eax
00E6171F mov eax,dword ptr [edx]
00E61721 call eax


vtable 使ってますね。当然


subA クラスにキャストして呼んでみる


((subA*)cls[0])->print();
00BD16F3 mov eax,dword ptr [cls]
00BD16F6 mov edx,dword ptr [eax]
00BD16F8 mov esi,esp
00BD16FA mov ecx,dword ptr [cls]
00BD16FD mov eax,dword ptr [edx]
00BD16FF call eax


vtable 使ってますね。


dynamic_cast使って subAクラスにキャストしてみる


dynamic_cast(cls[0])->print();
0031174D push 0
0031174F push offset subA `RTTI Type Descriptor' (318018h)
00311754 push offset base `RTTI Type Descriptor' (318000h)
00311759 push 0
0031175B mov eax,dword ptr [cls]
0031175E push eax
0031175F call @ILT+660(___RTDynamicCast) (311299h)
00311764 add esp,14h
00311767 mov dword ptr [ebp-150h],eax
0031176D mov ecx,dword ptr [ebp-150h]
00311773 mov edx,dword ptr [ecx]
00311775 mov esi,esp
00311777 mov ecx,dword ptr [ebp-150h]
0031177D mov eax,dword ptr [edx]
0031177F call eax

vtableですね



dynamic_cast使って subAクラスにキャストしてみる 更に メソッドにスコープつける


dynamic_cast(cls[0])->subA::print();
00301708 push 0
0030170A push offset subA `RTTI Type Descriptor' (308018h)
0030170F push offset base `RTTI Type Descriptor' (308000h)
00301714 push 0
00301716 mov eax,dword ptr [cls]
00301719 push eax
0030171A call @ILT+660(___RTDynamicCast) (301299h)
0030171F add esp,14h
00301722 mov ecx,eax
00301724 call subA::print (30100Ah)


キター
でも 遅そうですね


結論はこうです。 subAにキャストしつつ、printにスコープをつける


((subA*)cls[0])->subA::print();
0032170E mov ecx,dword ptr [cls]
00321711 call subA::print (32100Ah)


これが チョッパヤ
もちろん 安全性等考えると dynamic_cast 使うべきです。


おまけ


cls[0]->base::print();
00BD1710 mov ecx,dword ptr [cls]
00BD1713 call base::print (0BD115Eh)

((subB*)cls[0])->subB::print();
00251718 mov ecx,dword ptr [cls]
0025171B call subB::print (2511D6h)


スーパークラスにキャスト出来るのはわかるが、スーパーじゃないsubBにもキャストできて
一見正しく動く事もある(もちろん 絶対ダメ!)
こういうミス防ぐためには 速度犠牲になるけどdynamic_cast 使うべきなんだなぁ・・・


ただ、スーパークラスのメソッド呼べるのは場合によっては使うかもね。
知らない人はこの構文覚えるべし




しかし
((subA*)cls[0])->subA::print();
には問題がある。これは プログラマが subAである事を知っていないと成り立たない
つまり ポリモーフちゃんと出来ない。



if( typeid(cls[0]) == typeid(subA) )
{
((subA*)cls[0])->subA::print();
}
else if( typeid(cls[0]) == typeid(subB) )
{
((subB*)cls[0])->subB::print();
}else{
cls[0]->base::print();
}


こんな感じで RTTI情報を見て処理分ければ
速くできる可能性もある。ただし typeid の== 演算子がどうやら文字列比較してて
遅いので注意




結論から言うと ポリモーフィズムは普通にvtable使って呼ぶ
プログラム時に 型がわかっている時は
((subA*)cls[0])->subA::print();
こんな感じで vtableではなく、静的な関数アドレスを指定する

blogram投票ボタン
posted by ゆき at 23:28 | 東京 ☁ | Comment(2) | TrackBack(0) | C言語関連 | このブログの読者になる | 更新情報をチェックする
blogram投票ボタン
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。