はかせのラボ

私の頭の中を書いていく雑記ブログです

C++ コンストラクタの後ろにコロンつけてるやつの話 ~初期化子リスト~

あいさつ

どうも、はかせです。
今日はなんだかイマイチ頭が回らないので
DirectX12の勉強はお休みしました。

そのため今日は久しぶりのTips記事になります。

あなたがgithubとかでC++のコード読んでるとき
こんな感じで書かれているコンストラクタを見たことはありませんか?

class Hoge
{
public:
    Hoge() : hogeName("fuga"){}
private:
    std::string hogeName = "hoge";
}

今日はこの「:」がついたコンストラクタについての話です。

こいつは一体何?

この「:」の後ろについてるやつは
初期化子リストと言われるものです。

名前の通り初期化を行うものです。

書き方は変数名(初期値)になります。
ちなみにさっきみたいに最初っからメンバに値を設定していようと
初期化子リストで渡された値に初期化されます。
(つまりさっきの"hoge"は無駄である・・・)

こいつのメリットは何?

「初期化を行ってくれるってのはわかったけど
普通にコンストラクタにこんな風に書くんじゃダメなの?」

class Hoge
{
public:
    Hoge()
    {
        hogeName = "fuga";
    }
private:
    std::string hogeName = "hoge";
}

確かにごもっともな意見です。
私もそう考えていた時期もありました。

ただ使えるならばこの初期化子リストを使った方がいいです。
理由は以下の二点
・効率がいい
・const変数の初期化が行える

効率がいい

どういうことかというと
さっき上げたコンストラクタ内に書くやり方ってのは
実は初期化ではなく代入だということです。

メンバは実はしれっと各クラスのデフォルトコンストラクタで
初期化されています。

要はhogeNameはstringのデフォルトコンストラクタで
"hoge"に初期化されたのちに"fuga"という文字列を代入されているわけです。

これでは初期化+代入という二度手間が発生しています。

初期化子リストを使うことで
そこで渡した値で初期化を行えます。
つまりhogeNameは"fuga"という文字列で初期化されるわけです。

これなら一回の初期化で済みます。

const変数の初期化が行える

どういうことって言われそうなので
まずhogeNameにconstつけて
コンストラクタ内で代入してみます。

はいエラーでました。
当然ですよね。constは初期化しかできないんですから。
代入という動きになるこの書き方で
値を入れられないのは当然です。

たださっきも言ったように初期化子リストは
その値で初期化をするものなので
const変数の初期化ができます。

//エラーならない
Hoge(std::string name) :hogeName(name) {}

初期化子リスト有り無しでの実行結果を見てみましょう。
こんなコードで実行してみます。

//Hoge.hの中身
//(別にするのがめんどくさいわけでは決してない)
#pragma once
#include <string>
class Hoge
{
public:
	Hoge(){}
	Hoge(std::string name) :hogeName(name) {}
	const std::string hogeName = "hoge";
};
//Hoge.h終わり

//生ポ使ってるのも決してめんどくさいわけじゃ(ry
#include <iostream>
#include "Hoge.h"
int main()
{
	auto hoge = new Hoge();
	std::cout << "初期化子リスト無:" << hoge->hogeName << std::endl;
	auto hoge2 = new Hoge("fuga");
	std::cout << "初期化子リスト有(値=fuga):" << hoge2->hogeName << std::endl;
	getchar();
	delete hoge;
	delete hoge2;
}

結果です。

初期化子リストが無いやつは
最初に宣言したhogeという結果が出て、
有るやつは初期化子リストで宣言した
fugaという結果が出ています。

あとがき

今回は初期化子リスト、
通称コンストラクタの後ろに「:」つけてるやつ(筆者内で)
の話でした。

メンバの初期化という限定的な機能ですが、
効率がいいのとconst変数を初期化のタイミングでのみですが、
弄れるのはいいなと思っています。

あと初期化子リストって名前だと
std::initializer_list<T>ばっか当たって
「:」の方が出てこないんで
なんか別名つけて欲しいですね。

それでは今回はこの辺でノシ