为什么非 const vector<bool> 元素是 const?
Why are non-const vector<bool> elements const?
当我迭代 vector<bool>
时,我发现通过迭代器解除引用的元素被识别为就好像它们是常量一样。这是为什么?更改容器或元素类型,例如 list<bool>
或 vector<short>
,并且元素是非常量。此代码显示了我在说什么:
typedef bool T;
#define C vector
istringstream &operator>>(istringstream &iss, T &v)
{
cout << "non-const" << endl;
return iss;
}
istringstream &operator>>(istringstream &iss, const T &v)
{
cout << "const" << endl;
return iss;
}
istringstream &operator>>(istringstream &iss, C<T> &c)
{
for (C<T>::iterator it = c.begin(); it != c.end(); ++it)
{
iss >> *it;
}
return iss;
}
int main()
{
C<T> c(1);
istringstream iss("1");
iss >> c;
}
对于 vector<bool>
,此程序将 "const" 打印到控制台。将顶部的 typedef 和清单常量更改为除这两个组合之外的任何内容,它会打印 "non-const." 此外,如果我将行 iss >> *it
替换为 T v; iss >> v; *it = v;
,它会按预期工作 - - 所有组合打印 "non-const."
我在 GCC 4.1.2 C++98(通过 codepad.org)和 VS2015 C++14+(?)中看到相同的行为。
尽管名称如此,vector<bool>
不包含 bool
,并且取消引用其迭代器不会给您 bool&
。相反,它给你一个 vector<bool>::reference
类型的对象,它试图尽可能地模仿 bool&
的行为。
无法将 vector<bool>::reference
转换为 bool&
,因此非常量重载不起作用。但是,vector<bool>::reference
可以转换为 bool
,然后可以绑定到 const bool&
.
std::vector<bool>
是 std::vector
的特化,它充当 space-高效的动态位集。从 begin()
和 end()
返回的迭代器实际上指向代表布尔值的代理 class 类型的对象。
取消引用迭代器返回的引用是 class 类型的纯右值,而不是实际的布尔值。它被转换为 bool
类型的纯右值,因此这就是为什么重载引用 const 是优先的(右值可以绑定到对 const 的引用)。
为了节省内存,vector<bool>
不是 bool
的实际数组。一个 bool 值只需要存储一个位,但可能的最小大小是 1byte = 8bits。因此,通过不使用简单的实现,您可以获得比简单的 bool 数组提供的存储效率高 8 倍的存储效率(就内存而言)。
然而,结果是 vector<bool>
的元素不是 bool 而是 vector<bool>::reference
,它与 bool&
几乎但不完全相同。大多数操作都在这里,但有些不是(例如 |=
)
您仍然可以将它转换为 bool
,或者用它初始化一个新的 const bool
对象...然后用这个新对象做任何您想做的事情
当我迭代 vector<bool>
时,我发现通过迭代器解除引用的元素被识别为就好像它们是常量一样。这是为什么?更改容器或元素类型,例如 list<bool>
或 vector<short>
,并且元素是非常量。此代码显示了我在说什么:
typedef bool T;
#define C vector
istringstream &operator>>(istringstream &iss, T &v)
{
cout << "non-const" << endl;
return iss;
}
istringstream &operator>>(istringstream &iss, const T &v)
{
cout << "const" << endl;
return iss;
}
istringstream &operator>>(istringstream &iss, C<T> &c)
{
for (C<T>::iterator it = c.begin(); it != c.end(); ++it)
{
iss >> *it;
}
return iss;
}
int main()
{
C<T> c(1);
istringstream iss("1");
iss >> c;
}
对于 vector<bool>
,此程序将 "const" 打印到控制台。将顶部的 typedef 和清单常量更改为除这两个组合之外的任何内容,它会打印 "non-const." 此外,如果我将行 iss >> *it
替换为 T v; iss >> v; *it = v;
,它会按预期工作 - - 所有组合打印 "non-const."
我在 GCC 4.1.2 C++98(通过 codepad.org)和 VS2015 C++14+(?)中看到相同的行为。
尽管名称如此,vector<bool>
不包含 bool
,并且取消引用其迭代器不会给您 bool&
。相反,它给你一个 vector<bool>::reference
类型的对象,它试图尽可能地模仿 bool&
的行为。
无法将 vector<bool>::reference
转换为 bool&
,因此非常量重载不起作用。但是,vector<bool>::reference
可以转换为 bool
,然后可以绑定到 const bool&
.
std::vector<bool>
是 std::vector
的特化,它充当 space-高效的动态位集。从 begin()
和 end()
返回的迭代器实际上指向代表布尔值的代理 class 类型的对象。
取消引用迭代器返回的引用是 class 类型的纯右值,而不是实际的布尔值。它被转换为 bool
类型的纯右值,因此这就是为什么重载引用 const 是优先的(右值可以绑定到对 const 的引用)。
为了节省内存,vector<bool>
不是 bool
的实际数组。一个 bool 值只需要存储一个位,但可能的最小大小是 1byte = 8bits。因此,通过不使用简单的实现,您可以获得比简单的 bool 数组提供的存储效率高 8 倍的存储效率(就内存而言)。
然而,结果是 vector<bool>
的元素不是 bool 而是 vector<bool>::reference
,它与 bool&
几乎但不完全相同。大多数操作都在这里,但有些不是(例如 |=
)
您仍然可以将它转换为 bool
,或者用它初始化一个新的 const bool
对象...然后用这个新对象做任何您想做的事情