bool型を扱うときに注意すること

主にC++でbool型を扱うときに注意することを覚えているうちに書いておく。
まず、当たり前のことから。

	assert( sizeof(bool) == 1);
	bool hoge;
	assert( sizeof(hoge) == 1);

	const int N = 10;
	assert( sizeof(bool[N]) == N );
	bool piyo[N];
	assert( sizeof(piyo) == N );

trueかfalseの2通りしか値をとらないんだから、1byteはもったいない気もするけど、原則一つのbool値に1byteが割り振られる。
vectorだとまた話が違ってくる様だけど、そもそもvectorは使わない方がいいという話はよく聞く(理由はよく分かってない)。
bool値のサイズ自体でトラブルが生じることはそんなに無いように思う。メモリ制限が厳しい問題だと知ってて損はしない、という程度。
bool値でどういう事故が起こるかを説明するのが面倒なので以下のコードを実行してみよう。

#include <cstdio>
#include <cassert>
#include <cstring>
#include <algorithm>
using namespace std;

int main(){

	bool hoge = true, fuga = 42;
	printf("%d %d\n", hoge, fuga);
	assert( hoge );
	assert( fuga );

	assert( hoge == true );
	assert( fuga == 1 );

	assert( fuga != 42 );

	assert( hoge == fuga );

	const int N = 10;
	bool piyo[N];
	memset(piyo, -1, sizeof(piyo));
	
	//最善と思われる解決策
	//memset(piyo, true, sizeof(piyo));

	printf("%d\n", piyo[0] );
	assert( piyo[0] );
	assert( piyo[0] == true );
	assert( true == hoge );
	assert( piyo[0] != hoge ); //???
	//assert( piyo[0] == true && true == hoge && piyo[0] != hoge);

	int count_true1 = 0, count_true2 = 0;
	for(int i=0; i<N; i++){
		if(piyo[i] == hoge) count_true1++;
		if(piyo[i] == true) count_true2++;
	}
	printf("%d %d\n", count_true1, count_true2);

	assert( !(piyo[0] ^ true) );
	assert( piyo[0] ^ hoge ); //???

	assert( count(piyo, piyo+N, false) == 0 );
	//assert( count(piyo, piyo+N, true) == N );

	puts("end");
	return 0;
}

これだと全てのassertに引っかからずに正常に処理が終了する。
理不尽なのは2つめのコメント部分を実行するようにすると引っかかってしまうということだ。もしかしてbool変数に0,1以外の値を代入することって未定義な操作なんだろうか。
競技プログラミングやっていてどんな実害が出たかといえば、3つめのコメント部分で引っかかった。trueの数とfalseの数がともに0、という状況が発生して意味不明だった。当然デバッグもやりづらい。
こういう面倒なことが起きたのは主にmemsetで~0を使って初期化していたことが原因な気がする。どうせbyte単位で処理されるんだから、memsetの初期化はtrueを使う方がよいのだと思った。

結論

bool型変数にはなるべくtrue, false(1, 0)以外の値は代入しないようにしましょう。