Program: C:\WINDOWS\SYSTEM32\MSVCP140D.dll File: c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.12.25827\include\vector Line: 2219 Expression: vector<bool> iterator not dereferencableのように"vector<bool> iterator not dereferencable"なるエラーが出てしまった。
Vectorのイテレータが参照解決できない?これはおかしいと思い調べていると、 C++ Reference vector_bool のようにstd::vectorはboolに関してのみ特殊な実装をしていることが分かった。
Bool型自体にはC++では処理系により4Byteだったり1Byteが割り当てられるのだが、 論理的には1bitあればよいので無駄である(実際はintとの互換性やcpuにとっての 扱いやすさのため多めにとっていると思われる)。 これをそのまま配列にしては一層無駄が大きいから、std::vector
しかしこの代償として、std::vector<bool>が内部に確保した領域を直接bool& などで参照することはできなくなっている。
#include <vector> #include <iostream> int main() { std::vector<bool> vec{true, false, true, false}; for(auto it = vec.begin(); it != vec.end(); it++) { bool& b = *it; // これはできない b = true; std::cout << *it << std::endl; } }
g++だと上記のコードはちゃんとコンパイルエラーにしてくれている:
main.cpp: In function ‘int main()’: main.cpp:8:15: error: cannot bind non-const lvalue reference of type ‘bool&’ to an rvalue of type ‘bool’ bool& b = *it; ^~~ In file included from /usr/include/c++/7/vector:65:0, from main.cpp:1: /usr/include/c++/7/bits/stl_bvector.h:80:5: note: after user-defined conversion: std::_Bit_reference::operator bool() const operator bool() const _GLIBCXX_NOEXCEPT ^~~~~~~~
この問題の手っ取り早い対策としては、メモリ消費が問題でなければbool値も std::vector<char>などにキャストして格納してしまえばよい。
上のコードもbool -> charの置き換えで問題なく動作した。
なおVisual Studioではこのassertが暴走していることがあるようで、単なる out-of-range index (長さ10の配列の11番目の要素にアクセスした) で "vector<bool> iterator not dereferencableの エラーが出ていた (ダメじゃん)。