yoppa.org


Blog

openFrameworks、なんでポインタを使うのか?

openFrameworksをワークショップや授業などで教えていると、ポインタの概念にさしかかった時に突然抽象的になってしまい、挫折する人が出てきてしまう。自分のためのメモも兼ねて、なぜポインタを使うのか、抽象的な解説ではなくopenFrameworksでの分かりやすい実例をベースにして考えてみた。

ダメな例

例えば、以下のように画像をランダムな場所に表示するShowImageという簡単なクラスをつくったとする。

ShowImage.hpp

ShowImage.cpp

これを、ofAppから繰り返し生成して配列に格納し、表示していく。画像ファイルの読み込みはofAppで行い、ShowImageクラスに読み込んだ画像を代入していく。

ofApp.h

ofApp.cpp

これを実行するとどうなるか。画像のファイルサイズにもよるが、みるみるうちにメモリを消費していき、FPSも極端に落ちていく。実行しているマシンのメモリサイズにもよるが、ずっと起動していると最終的にはアプリごと落ちる。全然ダメダメなプログラムだ。

ポインタで指し示す

では、どのようにすればパフォーマンスが改善するのか? 「ダメな例」の最大の問題は、ShowImageにイメージを代入しているので、ShowImageクラスをインスタンス化して画像を代入する毎に画像ファイルの容量だけメモリを消費している。代入しているということは、つまりは画像のデータをそのままコピーしている状態になっている。

ここで、ポインタを活用する。ポインタのざっくりしたイメージは、データの実態ではなく、その参照先を「指し示して(Point)」いる機能だ。例えば、先程の例だと巨大な画像データの実態そのものをコピーしてくるのではなく、あそこに画像のデータがあるよと「指し示す」ことができる。

ShowImageから画像を描画する際には、imageは実態ではなくその参照先を指し示すポインタ *image になったので、以下のようにアロー演算子 “->” を使用するように変更する。このアロー演算子の形が、まさに指し示す矢印の形になっている。

ざっくりとしたイメージを図示するとこんな感じか?

pointer_image2.jpg

改良したプログラム

「ダメな例」を修正して、画像像を直接コピーするのではなく、ポインタとして指し示すように変更したプログラムは以下のようになる。

ShowImage.hpp

ShowImage.cpp

ofApp.h

ofApp.cpp

これで、ずっと起動していてもイメージ1個だけのメモリしか消費せず、ShowImageからはそのイメージのデータを参照しているだけなので、安定して稼動するプログラムになるはず! (とはいえ、永久にオブジェクトを複製し続けるので、ずっと起動してると落ちるかも…)

追記: 参照渡し

何人かの方から、この例ではポインタではなく参照をつかったほうが良いのではないかという指摘がありました。どちらが適切なのか、ポインタと参照のどちらをまず覚えるべきなのか、いろいろ難しい議論ですが、とりあえず、ポインタ渡しではなく参照渡しをして描画する例を掲載します。(間違いあればご指摘を)。

ShowImage.hpp

ShowImage.cpp

ofApp.h

ofApp.cpp

たしかに、参照渡しを使うほうが、わかりやすいような気もしてきた… C++は奥深い…