のりブログ

ゲーム関連記事および雑記などを書いています。

【C++】constを付ける理由。付ける派と付けない派の大きな違い。constの使用例やメリット・デメリット。

こんにちは!のりです。

今回は結構上級者向けの内容です。え?constって変数を定数として定義したり、Get関数内でメンバ変数の値を変更できないようにしたりしてプログラムコードの可読性を上げるために付けるやつですよね?と思った方は甘いです!(/・ω・)/

今回の話はそんな簡単な話ではないのです。

constには可読性を上げるメリットがあり、開発後半になってから全ての関数にconstを付けるのは大変だから最初から付けておくのが重要といった話をよく聞きます。

その一方でconstが付いた関数内でメンバ変数の値を変更するような仕様変更があったり、せっかくのconst変数の値を変更しないと変更箇所が大きくなりすぎるので開発期間的に仕方なくconstを解除したりすることもあり、その手間が面倒なので何でもかんでもconstをつけるのはよくないのではないか?仕様変更しづらいのがconstのデメリットだなんていう方もいると思います。

前者の方も後者の方もどちらも間違っていないと思います。まあ、前者の方は絶対的に後者は良くないというでしょうが。(;^ω^) 後者の言い分もゲーム業界など仕様変更が日常茶飯事な場合は決して間違ってはいないと思います。もちろん、最初から最後までconstを付けて仕様変更しないのがより良いことでもあると思います。

さて、constをとにかく付けたがる方をconst教なんて呼んだりします。そのくらい、constをつけることが絶対的正義だという方がいる一方で、どっちでもいいんじゃないか?むしろ、付けない方が変更しやすくて好きなんて方もいます。メリット・デメリットの話をしてもこの話は平行線ですが、基本的にはconst派の方がconstを付けろ!と言ってconst付けない派の方が分かりました。と承諾しながら、時間が経つと付けなくなるといったイタチごっごとなることが多いです。

こんなconstを付けるか付けないかの話ですが、実は付ける派と付けない派の本当の差はメリット・デメリットの話とは全く別の場所にあるということを今回書いてみたいと思います。

 

スポンサーリンク

 

目次

constの使用例、メリット・デメリット

constの使用方法やメリット・デメリットについて簡単に説明します。

(static const int X = 0; みたいな変数を定数として使用する使い方は割愛させていただき、主に関数へのconst使用について説明します。)

 

【constの使用例】

① const int GetX();

戻り値が参照やポインタでない通常の変数であればconstを付ける意味は無し。constを付けることも記述上は可能だが、int GetX() と意味は同じ。コンパイラ設定によってはエラーまたは警告扱いになる。

 

② const int& GetX();

参照の戻り値にconstを付けた場合、const int& x = GetX(); といった感じで取得した時に値の変更が禁止となる。

どうしても受け取り側が変更したい場合、int& x = const_cast<int&>(GetX()); といった感じで強制的に解除することはできるが推奨はされない。

const StructX& GetX(); といった構造体やクラスなどを返す場合、const StructX& x = GetX();といった取得方法となり意図的にStructの中身を変更できないようにするといった使用方法が多い。

取得時に値を変更したい場合は、 StructX& GetX(); というconstを外した関数も用意してconst StructX& GetX(); と StructX& GetX(); といった感じで2つの関数を実装する方法が一般的。

 

③ const int* GetX();

ポインタの戻り値にconstを付けた場合も②と同じように取得時に値の変更が禁止される。こちらも int* x = const_cast<int*>(GetX()) といった強引な解除が可能だが推奨はされない。

取得時に値を変更したい場合は②と同じく、const int* GetX(); と int* GetX(); といった感じで2つ関数を用意する。

const char* GetString(); といった感じで文字列の定数を返す関数で使用することが多い。

 

④ int ClassX::GetX() const;

クラスのメンバ関数名の後ろにconstを付けると、メンバ関数内でメンバ変数の値変更を禁止する。int ClassX::GetX() const { m_a = 2; return m_a; } など仮にm_a というメンバ変数を変更するとコンパイルエラーになる。

主にconst教、constつける派の方が重要視するのはこのメンバ関数へのconst記述。①~③までの記述方法は個々人の好みで付けたらいいとなるが、④だけは絶対付けろ!ということが多い。const付けたくない派も一番付けたくないのはこの④。

 

⑤ const int* ClassX::GetX() const;

②や③と④の複合系。受け取り側が値変更禁止、且つメンバ関数内の値変更禁止となる。const付けたくない派の方がconst付けたい派の方に付けろ!付けろ!と強制されると付ければいいんだろ!とやけになって最初と最後両方にconstを付けて const int Class::GetX() const; みたいな最初の const は意味がない文を書いたりすることがある。改めて言うが、②、③は意味があるが、①は意味がない。

ちなみにメンバ関数であれば、②は const StructX& GetX() const; ③は const int* GetX() const; と書くのが理想形。

③について、const char* GetString() const; みたいな記述はよく見る形。

 

【メリット】

②、③のような書き方は受け取り側が値を勝手に変更しないので可読性が上がりバグも減る。④、⑤のような書き方も可読性が上がりバグが減る

 

【デメリット】

④、⑤のような書き方は、メンバ関数内で値変更をするとコンパイルエラ―になるので値変更したらすぐに実装できるようなことをすぐ実装できなくなる。constを付けた側は値を変更してほしくないと思って付けたものだが、変更した方が実装期間が早いことも多い。

 

const付ける派、付けない派の違い

上記のconst使用例とメリット、デメリットを正しく理解していれば何となく付けた方がいいと思う方も多いかもしれませんが、それでも検証中のコードなどでちょっと値変更しようとしたらコンパイルエラ―になってconstめぇ!となってconstを消してしまう方もいるのではないでしょうか。

さて、このちょっと変更したらコンパイルエラ―になってしまう点をむしろ変な変更をすぐにエラーにしてくれるからメリット、すぐに変更できなくて不便だからデメリットと思うことでconstを付ける付けないの認識の違いとはなるのですが、実はもっと大きな理由があります。

 

【constを付ける派35歳以上(1985年生まれ以前)に多い、const付けない派または付けても付けなくてもいい派35歳以下(1985年生まれ以降)に多い】

「年の功」でベテランの方がconstのメリットを深く理解しているから付ける人が多いというだけではないのか?という声が聞こえてきそうですが、まあその認識でも合っています。しかし、その理由だけではconst教と言われるほどconstに執着がある方がいることを説明できません。

ゲームプログラマをしている35歳以下の方であれば、35歳以上のベテランの方からメンバ関数にはconstを付けろ!としつこく言われたことがあるのではないでしょうか?付けても付けなくてもいい派の方は了解です!ってな感じで付けると思いますが、付けたくない派の方はいまいち納得いかずにもやもやしている方もいるのではないかと思います。

このconstを付けなければならない理由を探すためにconstのメリット・デメリットを調べる方も多いと思いますが、結局はメリットもデメリットもあるので絶対的に付けることには納得がいかないのではないかと思います。

さて、なぜ35歳以上の方にconstを付けろ!付けろ!としつこく言うconst教の方がよくいるのでしょうか?35歳以下の方はconstを付けた方がいいとは思うが、周りに付けろ!付けろ!という言うほどの情熱はない方が大半だと思います。これにはある理由があります。

 

C言語からC++言語への移行を経験した方PS2からPS3への移行。】

ついに今回の話の結論です。なぜ35歳くらいを境にconst付ける派と付けない派、どちらでもいい派の分布が分かれるかというと、C言語からC++言語への移行を経験したかどうかが大きく影響しています。

会社に22歳で新卒入社した方が現在35歳というと13年前となります。2020年から13年前というと2007年です。この頃のゲームハードといえば、PS3WiiXbox360なんかが出始めた頃です。ゲーム会社もPS2の開発からPS3の開発へと変わり、そこで大きく変化したことがあります。開発言語の主流がC言語からC++言語に変わったことです。

 

constC++言語専用予約語C言語に存在しない。】

知っている方も多いと思いますが、実は const は C++ 専用の予約語です。C言語にはありません。C言語からC++言語に開発環境が移行する時、当時の開発者達は class といったC++の代名詞はもちろんのこと、constといった新機能をいかにスタイリッシュに使いこなすかがトレンドでした。

 

constをつけることも重要な業務

この時、会社によっては class のメンバ関数には全て const を付けろ!全てconst関数にするのだ!今日は時間を使っていいから、constが付いていない関数全てにconstを付ける作業をしろ!なんて職場もあったようです。このような職場を経験した方は、constを付けろ!と常日頃から言うことが当たり前で、人によってはconst教と呼ばれるほどにconstを付けることに使命を見出していたのでしょう。

 

35歳以下(1985年以降)の方はこのconst付け業務経験していない

そして、このconst付け業務及びCからC++への移行をリアルな職場で経験していない世代の方はぶっちゃけピンときません。なぜそこまでconstを付けることにこだわるのか。ちょっと付け忘れたくらいでなぜそこまで最重要事項のように付けろと騒ぐのか理解に苦しみます。(笑) 

 

const付ける派付けない派互いに理解するためにはこのジェネレーションギャップといえるCからC++への移行説明して理解する必要がある】

constを付けて当たり前の時代を生きた方とconstは付けた方がいいとは聞いているくらいの認識の方が互いに理解し合うためには、constのメリット・デメリットを説明しただけでは不十分です。付けろと言う側の方は、C++へ移行する時代の話も織り交ぜながらメリットを説明してあげて、付けない派の方も付けろと言う人はきっとconst付け業務を経験してきた人だからデメリットなんて言っても聞く耳を持たないと理解してあげることが重要だと思います。

まあ、constを付ける派の方は年上の方が多いということになるので、必然的に上司になりこの歴史的な事情を知らないと上司部下の関係が悪くなることさえあるので、たかがconstと侮らずに互いに理解することが重要だと思います。

 

スポンサーリンク

 

あとがき

ということで、constについてのお話でした。私自身、const付ける派、const付けない派、どちらでもいい派の方を職場で見かけることがあり、メリットがあるならなぜ全員const付ける派じゃないのか?なぜ頑なに付けない派の方もいるのか?どちらでもいい派の方は聞けば付けた方がいいと答えるのに実際は付けなかったりするのはなぜか?など疑問に思うことがあったので思い切ってそれぞれの派の方に話を聞いてみた結果、メリット・デメリットの他にCからC++への移行という大きな要因が判明しました。

ちなみに、どちらでもいい派の方はC++への移行どころか、メリット・デメリットもあまり深く理解していない場合が多く、結果としてどっちでもいいんじゃないのか?という適当な認識という場合が多かったです。

constとは別の話ですが、最近だと std::unique_ptr を使え!みたいな人が多いですね。C++11で追加された機能でメリットが大きいので使う方も多いと思いますが、数年後にはなぜ生ポインタではだめなんですか?という若い方が増えるかもしれませんね。(;^ω^)

以上、constを付ける理由。付ける派と付けない派の大きな違い。constの使用例やメリット・デメリット。でした。