昨日のC++の記事は少し誤解があった。
実はC++ではオブジェクトが破棄されるときデストラクタというのが実行される。
これによりメモリなどを解放することになる。
それで、Hoge a=Hoge(100);などして作ったオブジェクトは、
そのローカル変数aが使われなくなった時点でデストラクタが呼び出され破棄される。
一方Hoge* b=new Hoge(100);などして動的にメモリを確保して作成したオブジェクトは、
自動では破棄されず、delete b;する必要があると。すっかり忘れてた。
というわけでローカル変数にのみ使う場合はnewで確保しない方がいいですね。
そちらの方が安全と。C#のusing構文のような機能が自動でついているということです。
しかしオブジェクトを作ったところで破棄しない場合はnewで確保するべき。
その上でSTLライブラリの話をしようと思う。
STLは動的配列やらなんやらとにかくデータを投げ込むコンテナやらを提供するライブラリ。
現在はC++の標準ライブラリとなってて、空気のように使われます。
配列ほど高速じゃないとは思うけど、大きさの定めなく配列を作れるので便利かなと。
#include
#include
#include
class Doing{
public:
void operator()(int cur){
std::cout << cur*100 << std::endl;
}
};
int main(){
std::vectorlist;
list.push_back(100);
list.push_back(20);
list.push_back(5);
for(std::vector::iterator cur=list.begin(); cur std::cout << *cur << std::endl;
}
std::for_each(list.begin(),list.end(),Doing());
return 0;
}
使い方は、#include
push_backメソッドで追加していく。
それでlist[2]などして要素は読めるし、sizeメソッドでオブジェクトのデータ数も読めるのですが…
繰り返し操作にはイテレータが使われるのが普通です。
list.begin()で初めの要素を指すイテレータを得て、++curで勧めて、list.end()に満たないうちは進むと。
++curですが、僕に取っては慣れない書き方なのだが、C++では普通++curのように書きます。
というのもcur++の場合オブジェクトを複製する必要があるらしい。++curの場合それが不要になる。
C++なのに++cと使うことの方が多いわけです。Cではc++と書くのが普通でしたけど。
もっともC++でもint型などはオブジェクトの複製なんて気にすることではなくて、c++のような表記でも問題ない。
まぁこれが1つの方法ですが、もう1つstd::for_each関数を使う方法があります。#include
それで引数ですが、最初の要素を指すイテレータ、終わりを指すイテレータ、それと関数オブジェクトなんですね。
関数オブジェクトってなんじゃという話ですが、もっともシンプルなのが上に用意したDoingクラスですね。
()演算子をオーバーロードしてますけど、これは関数呼び出し演算子と言います。
これをオーバーロードすれば、Doingクラスのインスタンスをfoo()のように関数ポインタのように取り扱えると。
他にも関数オブジェクトはあるけど、これがもっともわかりやすい。
しかしながらいちいち関数オブジェクト作るのめんどくさい。
それでいろいろ調べてたのだが、いいものがあった。Boostですね。
Let’s Boostが非常に参考になります。ここのインストール方法を見てインストールしましょう。
ヘッダーファイルなどの固まりをダウンロードして展開。
僕はこのフォルダをC:\borland\bcc55\boostとすることにした。なんか変な場所だが好きなところに置けばいいんです。
それでBinのbcc32.cfgの-Iの””の中に;C:\Borland\bcc55\boostを書き足す。
これでBoostが使えます。
さて、このLet’s Boostの関数型プログラミングのところのlambdaの説明を読むと、
簡単に関数オブジェクトが作れることがわかります。ありがたいですね。
#include
using namespace boost::lambda;
std::for_each(list.begin(),list.end(), std::cout << _1*100 << "\n" );
最後にstd::endlを使うとうまく行きませんね。最後は文字列で終わるとよさそう。
どうもBorland C++ Compiler 5.5はコンパイラの限界でこういう問題が起きるそう。
というわけでVisual Studioについてきた、Microsoft製のコンパイラを使おう。clですね。
C:\Program Files\Microsoft Visual Studio 8\Common7\Toolsのvsvars32.batで、
@set INCLUDEの行の最初にC:\Borland\bcc55\boost;を書き足しておきましょう。
それでVisual Studioコマンドプロンプトでclを使うと、うまくコンパイルできて、実行できる。
さらにはこんなこともできる。
int x=0;
std::for_each(list.begin(),list.end(), x+=_1 );
std::cout << x << std::endl;
なんでもないように見えますがxというのはローカル変数ですね。
作られた関数オブジェクトはこのローカル変数のxをいじることができると。
これは結構すごいことなんですよ。これを平然とやってのけるのはすばらしいですね。
なお、foreach自体は他にも実現方法があります。
というのはBOOST_FOREACHというマクロですね。#include
BOOST_FOREACH( int &cur,list){
x+=cur;
}
STLのオブジェクトの他に、静的に確保した配列も使えます。
ただしマクロなので、所々問題はありますが。たとえば受ける変数の型名に,が入ってたらだめだとか。
しかしなかなかおもしろいですね。
C++の足りない部分を補えるかも知れない。
C++の演算子オーバーロードとかテンプレートが強力すぎて実現できたことですから、
実は足りないことではなかったのかも知れませんけど。