Version 4.15
const 再び
「前回、ポインタの使用例でこういう関数を紹介しました」
void RetTwoValueToPointer( int *p_piRet1, int *p_piRet2 )
{
*p_piRet1 = 100;
*p_piRet2 = 200;
}
『値をふたつ返すためにポインタを使う、って例だよね』
「つまり、引数にポインタを使うメリットのひとつは、値を返すことができ
る、ってこと」
『ってことは、他にもメリットがあるんだ』
「そう。もうひとつのメリットは〈新たに作る変数はポインタ〉って点」
『どゆこと?』
「関数の引数は〈変数の一種〉だから、新しく作られます」
『かなり昔にそんなこと言ってたね』
「 Ver 2.10 ( No.021 )だね。で、まずポインタとか使わない場合。 int
型の変数を作って、引数も int 、つまりポインタや参照じゃない場合」
『んっと、たとえば関数が F( int p_i ) みたいな感じで、それを F( i )
みたいに呼ぶってことよね』
「そうそう。この場合、元の変数と、引数の変数と、変数がふたつ作られる
ことになります」
『あー、そう考えるとなんか無駄って感じ』
「ま、こんくらいコンピューターには負担になんないけどね。ちなみにこう
いう〈ポインタや参照を使わずに渡す〉ことを〈値渡し〉って言います」
『ねわたし?』
「そ、値を直に渡すから。それに対して〈ポインタや参照を使って渡す〉こ
とを〈参照渡し〉っていいます」
『ポインタ渡しって言わないの?』
「話がこんがらがるけど、ポインタも、一般の意味での〈参照〉だから」
『あー、240ページ開いて、みたいな意味だよね。確かにアドレス値がそ
ういう役目だもんね』
「さて話を戻しましょう。ポインタを使って渡した場合」
『 F( int *p_i ) で F( &i ) みたいな感じだよね』
「この場合、元の変数と、引数のポインタ、変数がふたつ作られます」
『……おなじやん! ってツッコミ入れていいんだよね』
「そう。ポインタも変数の一種だからね。ところが、元の変数が〈クラス〉
の場合には話が違ってきます」
『お、懐かしい言葉! 変数に変数が入ってたり、関数付いてたりするのだ
よね』
「そうそう。クラスには〈メンバ変数〉っていう機能があって、中にいっぱ
い変数を入れることができます」
『詳しくは Ver 3.7 ( No.032 )だね。いっぱい変数が入ってるってことは、
メモリいっぱい食いそうだね』
「そうそう、 int は4バイトだったけど、クラスはその何倍にもなります。
さて、このクラス型変数が〈元の変数〉だった場合」
『値渡しの場合……他にクラスって知らないから CDialog で書くけど、
F( CDialog p_cDlg ) で、 F( cDlg ) って呼ぶ感じだよね』
「そう。この場合、元の CDialog と、引数の CDialog 、ふたつが作られた
わけ」
『対して参照渡しの場合…… F( CDialog *p_cDlg ) で、 F( &cDlg ) 、
同じって気もするけど』
「そう? ポインタのサイズは?」
『 int と同じ4バイト。あ……ってことは、参照渡しだと、元の CDialog
と引数の CDialog のポインタを作るんだから』
「引数の方の変数のサイズについて見れば、参照渡しの方がサイズが小さく
なるわけ」
『値渡しだと CDialog でかなり大きい、参照渡しだとポインタだから4バ
イト。なるほど』
「その他にも参照渡しのメリットがあったり」
『あのさ、前回出てきたから見返したんだけど、Ver 3.22 ( No.047 )でやっ
た theApp って複製作れないでしょ、それって値渡しできないってことじゃ
ない?』
「そう! よく気が付きました。クラスは仕様によっては複製が作れない場
合があるから、そういう場合には参照渡しじゃなきゃダメ。よく気が付いた
ねー」
『うふふふふ』
「で、ここまでが前振り」
『なんの?』
「参照渡しのメリットは、値を返すだけじゃないよー、ってこと」
『なるほど。で、タイトルと合わせて鑑みると、それはつまり〈参照渡しで
値を変えられるのは危険!〉とかなって、 const 使うんでしょ』
「う”お、なんか先読みですね」
『ふふふ、今日はなんか冴えてるの』
「ではその通りというわけでこの関数」
void ConstPointer( const int *p_piConst )
{
TRACE( "%d\n", *p_piConst ); // 100
// *p_piConst = 100; // ビルドするとエラーになります。
}
// 下の関数を呼んでください。
void CallConstPointer()
{
int i = 100;
ConstPointer( &i );
}
『えーっと? あ、まず引数が const int のポインタになってるね。こ
れって Ver 4.12 ( No.062 )で出てきたのだよね』
「そう、まったく同じもの。普通の変数を〈リードオンリーなポインタ〉に
したいときに const なポインタを作ります」
『あ、そうなると ConstPointer() の中から i に書き込みできないんだ』
「上のコメントアウト取り除いてビルドすると……」
error C2166: 左辺値は const オブジェクトに指定されています。
『これも同じエラーだね』
「こんなふうに、ポインタだけれども値を返さないようにすることができる
ってことだね」
『ってことはさ、参照も同じふうにできるの?』
「そう、できるんです」
void ConstReference( const int &p_riConst )
{
TRACE( "%d\n", p_riConst ); // 100
}
// 下の関数を呼んでください。
void CallConstReference()
{
int i = 100;
ConstReference( i );
}
『あ、なんかほとんどポインタと同じだね』
「でしょう。ポインタとの違いは * が & になってるのと、 & と * がなく
なってるとこ」
『ふーん……』
「どしたの?」
『この前も思ったんだけど、 const 参照って、なんか違うかなーとか』
「ってゆーと?」
『もともと、ポインタってメモリとかアドレスとか、そういうのだったで
しょ。それが const 参照になっちゃうと、そういう自由度が全然ないって
ゆーか、なんかポインタと別もんってゆーか』
「そう、それが目的だからね」
『それが目的?』
「たとえば〈あるクラス型変数を、コピーを作らずに他の関数から操作した
い〉っていう場合」
『そーゆーときに const 参照を使うわけだよね』
「別に使わなくてもいいでしょ?」
『え?』
「本当にただのポインタでも、同じことはできるでしょ」
『確かにねー。 * とか付けて、書き込みに注意すればいいんだから』
「昔の C 言語っていうのは、そういうものだったの」
『むかし?』
「そう、参照なんてない時代。ポインタっていう道具を駆使していろんなこ
とをしてたわけ」
『その分面倒だったんだよね』
「それに危険だった。 int &ri で ri[3] ってしたらどうなると思う?」
『 ri って参照だよね。ってことは……』
void ReferenceAndBrackets()
{
int i = 100;
int &ri = i;
ri[3]; // ビルドエラー。
}
『あ、エラー』
error C2109: 配列または、ポインタでない変数に添字が使われました。
『あ、ってことは参照って隣とか見れないんだ』
「そう。 * も使えないし、アドレスの足し算しようとしても」
『それって i の足し算とかになっちゃうよね。つまり参照だとアドレス操
作が全然できないんだ!』
「そういうこと。その分ポインタが持ってる危険度が少ないわけ」
『同じ参照渡しでも、ポインタより参照の方が安全ってことね。でもさ、元
はポインタなんでしょ?』
「そう、参照も、 const 参照も、 const ポインタも、基本的には普通のポ
インタ。それに制限が加えられたものってこと」
『確かに安全になるのはいいんだけど、ポインタの頃と、なんか感じが違う
かなーって』
「そうだね、参照とかって〈機能寄り〉かな」
『そういえば言ってたよね、必要な機能が先にあって、そのために道具が用
意されるんだって』
「元々はただのポインタだけだったんだけど、参照や const が必要になっ
たからどんどん付け加えられていったってこと」
『そうなっちゃうと、ポインタの面影がないよね』
「それはそうだよ。目覚まし時計使う時に、時計の中身のこと考える?」
『考えない。つまり時計そのものが参照で、中身はポインタ、ってこと?』
「何かの機能を使いたいときに、その仕組みは必要ないでしょ」
『でも……』
「火美ちゃんの気持ちは僕も分かるよ。あるひとつの道具を使いこなせると、
他の道具は要らないって思うもんだから」
『プ○ゴルファー猿みたいに?』
「ま、まぁ……」
『でもやっぱ、ゴルフにはアイアンとか必要だもんね』
「そう、場合によって道具を変えることが大事。火美ちゃん、僕が〈プログ
ラマーは自動車整備士なんだよ〉って言ったの憶えてる?」
『うん、憶えてる。 Ver 4.08 ( No.058 )で言ってたよね』
「火美ちゃんは今、自動車整備士の側になりすぎてるってこと。火美ちゃん
は〈ポインタ〉っていう中身の部分を急に知ったから、その視点にこだわっ
ちゃうんだよね」
『あ、つまり、車を乗る側に戻ってみればいいんだ!』
「そういうこと! 今火美ちゃんは〈変数の複製を作らずに関数に渡したい〉
と純粋に思った。なら?」
『参照を使うと便利! だよね?』
「これは何を作ることにも言えることだけど、クリエイターとユーザー、両
方の視点が大事」
『自分でクラブ作ってもそれに頼り切っちゃダメ、そのクラブが使えるかっ
て視点も大切、ってことね』
「なんかそれにこだわるね……」
/*
Preview Next Story!
*/
『なんかすごい哲学的……』
「そんな感傷に浸ってる暇はありません」
『ホントに押せ押せだもんね』
「う”、ポインタ編も伸びちゃったしなー」
『というわけで次回』
< Version 5.01 普通のアプリを作ろう >
「につづく!」
『なんか変なタイトル……』
「新章はふたたびちゃんとしたアプリを作ります!」
『なんかすごいいきおい……』