ポインタの参照渡し

調べてみるとC++の入門書にも書いてあるような内容らしいのですが、ポインタにも参照渡しというものが存在するということを今日初めて知りました。

プログラミングの教科書などは関数にポインタを渡して、そのポインタが指すオブジェクトの要素を変更すると、関数の外で見てもやはりポインタが指すオブジェクトの要素が変更されている、という話がよく書かれています。これは当然といえば当然で、関数の中と外で差しているポインタが同じなのだから、そのオブジェクトの値が変われば中でも外でも値が変わるというわけです。一応補足しておくと、C言語で値渡し(ポインタでも参照でもない引数を関数に渡すこと)をすると、値は一度コピーされて、関数の中ではそのコピーが使われます。

さて、こういうことをプログラミングを始めて以来、ずっと当たり前のように使ってきたわけですが、ポインタ自体を関数の中で変更したらどうなるのだろうかと思いました。具体的には、単方向の結合リストを再帰関数によってたどっていく場合に、関数の中でノードのポインタを次のノードのポインタに変更したいと思ったわけです。例えば次のような感じ。

void traverseList(Node* node) {
    node = node->next;
}

さて、こう書いた時に、関数の外でnodeの指すポインタが変わるかというと答えはNOで、ポインタが指すアドレスは変わりません。言われてみれば確かにそうで、上の話にのっとれば、nodeの指すオブジェクトの持っている値などを変更すれば、その時はオブジェクトの持つ値は変わるけれど、ポインタ自体が変わるとは一言も言っていないわけです。

と、いうことは、ポインタ自体にも参照渡しが存在するのか?と思ったところ、確かにありました。すなわち上のコードを次のように書き換えることで期待の結果を得ることができます。

void traverseList(Node*& node) {
    node = node->next;
}

なんとも奇妙な書き方ですが、これは「ロベールのC++入門」という本にも書かれているらしく、おそらく正しい書き方です。というわけでめでたしめでたし。今日も勉強になりました。