そこにconst、ここにconst、それがC++

boost::asio::ip::tcp::socketを使ってHTTPのリクエストを送り、レスポンスを受け取るメソッドを作ってた。
GETしかできないとか、レスポンスを始めに全部読み取ってしまうとかいう問題はあるけど、
POSTを使わない、大きなデータを扱わない限りは十分実用的と言えるでしょう。
POSTの実現方法自体は簡単だから必要なら用意しただろうが、必要じゃないので省略。
また整理したらここで取り上げようと思う。


ところでC++にはよくわからない文化がある。
というのはconstキーワードのことです。
JavaやC#のユーザーからすればconstキーワードというと定数を作るものだと思うが、C++では必ずしもそうではない。
その意義はJavaのfinalやC#のreadonlyに近い気もするがそれも違う気がする。

#include 
#include
void main(void){
std::vector v(1);
v.at(0)=19;
std::vector v2(0);
const std::vector &vref=v;
//vref=v2;
std::cout << vref.size() << std::endl;
std::cout << vref.at(0) << std::endl;
//vref.at(1)=4;
//vref.clear();
}

constキーワードというのは、そのオブジェクトは変更不可だよということらしい。
const std::vector &のように参照とくっつけて使われることが多いですね。
ちなみにconst std::vector &とstd::vector &は違う型として扱われるので注意。
もちろん変更不可なんだから代入はききませんよと。
けどsizeを呼び出してもちゃんと値を返してくれます。値を変えないメソッドには関係ありません。
しかし、atで取り出したオブジェクトを利用するのは問題ないけど、代入するのは無理。
これはconstをつけたときとつけなかったときでatの性質が変わって、
constつけたときは返す参照もまたconstであると。実はそういうことなんですね。
clearのようなメソッドも封じされてしまいます。


C++を始めて、一番混乱したのがこのconstキーワードのことですね。
C#ではconstキーワードは定数にのみ使うもので、引数にconstとかあり得なかったんですね。
constつけられるといろいろと制約が多いんですね。
そのことを知らなかったものだからコンパイルエラーは大量に出るしえらいことでした。
そもそもconstというのは定数に使うものだと思っていたから、僕は変数の性質がconstであると言っているのだと思っていたんですね。
けど実際はconst型とでも言うべきものだったんですね。これに気付くまで随分と時間がかかりました。
理解してしまえば、自分でこれをうまく応用できるようになりました。


constの使い道ですが、まずメンバ変数の参照を返すときですね。
メンバ変数への参照を渡してしまうと書き換えし放題、だからといって実体を渡すとコピーされて大変。
そこでconst std::vector&のような型を返り値にする。
すると送られるのは参照だからコピー不要、その一方で書き換えは阻止できる。
ただ使い方を知らないと混乱するかもね。受ける方はこうする。

const std::vector &vref=obj.GetRef();

それと引数を参照渡しで受け取る時ですね。
別にconst無くても作る方からすれば大した問題ではないですけど、
const型はconstを外すキャストはできないんですね。逆はできるんですけど。
だからconstな人にために変更しないならconstをつけておいてあげましょう。


自分でクラス作るときもconstの人への配慮を忘れないように。
どうするのかというと自分自身を変えないメソッドにはconstキーワードをつけておきましょう。

class Foo{
public:
int Size(void) const;
//中略
};
int Foo::Size(void) const{
//内容
}

このようにconstをつけます。なんでこんな場所にconstキーワード書くのかはわからないけどつけておきましょう。
そうすれば初めの例のsizeメソッドのようにconstだったとしても使えるようになります。
これも普通に使ってる分には役に立たんだろうと思うかも知れないけど、
constな人からすれば必要なことなんですね。


まぁこんな感じです。これでconstキーワードを活用できるかも。
C#やってた人からすると、スタックにオブジェクトの実体をおいておけることと、constキーワードは衝撃的でしたね。
どちらも扱いめんどくさいと思うのですが、C++では通常GCを使いませんからね。
スタックに実体をおいておけば解放いらんから、その点では有利とは言えるし、
constつけて参照渡しするのだって、C++では参照渡ししなければオブジェクトがコピーされるからで、
このあたりはC++では重要な道具なんですね。
郷に入りては郷に従えという言葉もありますが、C++ではこの流儀に従うことにしましょう。
というわけで適切なところでconstキーワードを使えるようになりましょう。