![](/img/trans.png)
[英]Why does “std::begin()” always return “const_iterator” in such a case?
[英]Why does std::set seem to force the use of a const_iterator?
考虑下面的简单程序,它尝试使用对集合中元素的非常量引用来遍历集合的值:
#include <set>
#include <iostream>
class Int
{
public:
Int(int value) : value_(value) {}
int value() const { return value_; }
bool operator<(const Int& other) const { return value_ < other.value(); }
private:
int value_;
};
int
main(int argc, char** argv) {
std::set<Int> ints;
ints.insert(10);
for (Int& i : ints) {
std::cout << i.value() << std::endl;
}
return 0;
}
编译时,我从 gcc 收到错误:
test.c: In function ‘int main(int, char**)’:
test.c:18:18: error: invalid initialization of reference of type ‘Int&’ from expression of type ‘const Int’
for (Int& i : ints) {
^
是的,我知道我实际上并没有尝试修改 for 循环中的元素。 但关键是我应该能够获得在循环内使用的非 const 引用,因为集合本身不是 const 限定的。 如果我创建一个 setter function 并在循环中使用它,我会得到同样的错误。
集合就像没有值的地图,只有键。 由于这些键用于加速集合操作的树,因此它们无法更改。 因此,所有元素必须是const,以防止底层树的约束被破坏。
std::set
使用包含的值来形成快速数据结构(通常是红黑树)。 更改值意味着需要更改整个结构。 因此,强制const
, std::set
阻止您将其推入不可用状态。
从cpp参考 :
在集合中,元素的值也标识它(值本身是类型T的键),并且每个值必须是唯一的。 集合中元素的值不能在容器中修改一次(元素总是const ),但可以在容器中插入或删除它们。
行为是设计的。
给你一个非const迭代器可以激发你改变集合中的元素; 随后的迭代行为将是未定义的。
请注意,C ++标准说set<T>::iterator
是const
所以老式的前C ++ 11方法仍然不起作用。
添加内特的答案:
集合就像 map,没有值,只有键。 由于这些键用于加速集合操作的树,因此它们不能更改。 因此,所有元素都必须是
const
以防止底层树的约束被破坏。
对于 C++17 有新的extract
成员 function,因此const_cast
的替代方案可能是:
#include <iostream>
#include <string_view>
#include <set>
struct S
{
int used_for_sorting;
bool not_used_for_sorting;
bool operator<(const S &rhs) const
{ return used_for_sorting < rhs.used_for_sorting; }
};
void print(std::string_view comment, const std::set<S> &data)
{
std::cout << comment;
for (auto datum : data)
std::cout << " {" << datum.used_for_sorting
<< ',' << datum.not_used_for_sorting
<< '}';
std::cout << '\n';
}
int main()
{
std::set<S> cont = {{1, false}, {2, true}, {3, false}};
print("Start:", cont);
// Extract node handle and change key
auto nh = cont.extract({1, false});
nh.value().not_used_for_sorting = true;
print("After extract and before insert:", cont);
// Insert node handle back
cont.insert(std::move(nh));
print("End:", cont);
}
可能用作热修复。 一般来说,很难看出比std::map
有任何优势。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.