プログラマーの卵の日記

備忘録になってます!小難しそうなことから超簡単なことまでやってます!!

【C++】範囲for文とfor文の違いについてよく見て見た

構成


No.1 何故この話か
No.2.1 (数値による範囲)よくあるfor文
No.2.2 (数値による範囲)範囲for文
No.3.1 (配列ポインタクラス)よくあるfor文
No.3.2 (配列ポインタクラス)範囲for文
No.4 要は







      No.1 何故この話か


 某ゲームプログラミングの本を読んでいたら、自分では全然使わない範囲for文が使われていました。
ぶっちゃけどういったものなのか理解していなかったので範囲for文について見つつ、色々試してたらいろいろな利点と欠点みたいのが見えてきたので
まとめてみようかと思いました。

 ただ、これは自分の見解ですし、正直C++の達人の方に質問して、実際のところどうなのか知りたいぐらいなので、読むなら温かい目でお願いします。

 あと、for文以外のコード部分はこうしています。


#include <iostream>
#include <vector>


class A
{
private:
	int hp;

public:
	A(const int t_hp) : hp(t_hp) {}
	~A() {}

	const int GetHP()
	{
		return hp;
	}
};


int main()
{
	return 0;
}






      No.2.1 (数値による範囲)よくあるfor文


 for文を勉強し始めたときに合計値とか出されると思うんですが、それをやってみるとこんな感じ。


	int sum = 0;
	for (int i = 0; i != 10; ++i)
	{
		sum += i;
	}


 いや、普通じゃんっていう話だけど、範囲for文だとそうはいかない。





      No.2.2 (数値による範囲)範囲for文


 上記の合計値を出すものですが、範囲for文では出来ません。
リファレンスの文を借りて言えば、「メンバ関数にbegin()およびend()を持つクラスであれば、何でも範囲for文の範囲として指定できる。」ということです。


 一応それっぽいのを書いてみますが、赤い波線がついて実行できません。


	int sum = 0;
	for (auto i : 10)
	{
		sum += i;
	}

	int sum = 0;
	const int num = 10;
	for (auto i : num)
	{
		sum += i;
	}






      No.3.1 (配列ポインタクラス)よくあるfor文


 よく使うfor文だとこんな感じだと思います。


	std::vector<A*> a(10);
	for (int i = 0; i != 10; ++i)
	{
		a.at(i) = new A(i);
	}
	for (size_t i = 0, n = a.size(); i < n; ++i)
	{
		std::cout << a.at(i)->GetHP() << "\t";
	}
	std::cout << std::endl;

 ・ループの始めと終わりの決める必要がある。
 ・添え字を利用することが出来る。





      No.3.2 (配列ポインタクラス)範囲for文


 コードにするとこんな感じだと思います。
比較のため、内容については先ほどと同じようにします。


	std::vector<A*> a(10);
	int ID = 0;
	for (auto& ia : a)
	{
		ia = new A(ID++);
	}
	for (const auto& ia : a)
	{
		std::cout << ia->GetHP() << "\t";
	}
	std::cout << std::endl;

 ・順番の数値を使うなら添え字を別途用意しないといけない。
 ・添え字が必要なければその分作る変数が減る。


 添え字を必要としないなら範囲for文の方がいいかもしれない。
ただ、範囲for文の欠点として、for文が始まるときにbeginとendを利用する形で行っているので、途中から数が増えたり減ったりしたら「イテレータが無効」となるため、エラーが起きる。
よく使う方のfor文だとイテレータ関係なく範囲を数値でやっているのでエラーにはならず普通に動きますね。


	std::vector<A*> a(10);
	for (int i = 0; i != 10; ++i)
	{
		a.at(i) = new A(i);
		a.push_back(new A(i));
	}
	for (size_t i = 0, n = a.size(); i < n; ++i)
	{
		std::cout << a.at(i)->GetHP() << "\t";
	}
	std::cout << std::endl;






      No.4 要は


 添え字の数値を使う必要があるのであれば、よくあるfor文でいいかもしれないが、
添え字を必要としないなら範囲for文を使った方が添え字の無い文見やすくなるかもしれない。

 ただ、調べていくうちにoperator[]を使ったりなどすれば添え字も取り出せるみたいです。
あと、範囲for文は忠実に回すので逆順が出来ないみたいです。boost使えば、なんか楽にできるみたいですが…。その他に、std::reverseを使えば配列自体が逆になるのでこれでもいいかもしれません。配列数が多い場合は良い判断とは言えないかもしれませんが。