[英]Why does std::set seem to force the use of a const_iterator?
Consider the simple program below, which attempts to iterate through the values of a set using NON-const references to the elements in it:考虑下面的简单程序,它尝试使用对集合中元素的非常量引用来遍历集合的值:
#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;
}
When compiling this, I get an error from gcc:编译时,我从 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) {
^
Yes, I know I'm not actually trying to modify the elements in the for loop.是的,我知道我实际上并没有尝试修改 for 循环中的元素。 But the point is that I should be able to get a non-const reference to use inside the loop, since the set itself is not const qualified.但关键是我应该能够获得在循环内使用的非 const 引用,因为集合本身不是 const 限定的。 I get the same error if I create a setter function and use that in the loop.如果我创建一个 setter function 并在循环中使用它,我会得到同样的错误。
A set is like a map with no values, only keys. 集合就像没有值的地图,只有键。 Since those keys are used for a tree that accelerates operations on the set, they cannot change. 由于这些键用于加速集合操作的树,因此它们无法更改。 Thus all elements must be const to keep the constraints of the underlying tree from being broken. 因此,所有元素必须是const,以防止底层树的约束被破坏。
std::set
uses the contained values to form a fast data structure (usually, a red-black tree). std::set
使用包含的值来形成快速数据结构(通常是红黑树)。 Changing a value means the whole structure needs to be altered. 更改值意味着需要更改整个结构。 So, forcing const
ness, std::set
prevents you from pushing it into a non-usable state. 因此,强制const
, std::set
阻止您将其推入不可用状态。
From the cpp reference : 从cpp参考 :
In a set, the value of an element also identifies it (the value is itself the key, of type T), and each value must be unique. 在集合中,元素的值也标识它(值本身是类型T的键),并且每个值必须是唯一的。 The value of the elements in a set cannot be modified once in the container (the elements are always const ), but they can be inserted or removed from the container. 集合中元素的值不能在容器中修改一次(元素总是const ),但可以在容器中插入或删除它们。
The behaviour is by design. 行为是设计的。
Giving you a non-const iterator could inspire you to change the element in the set; 给你一个非const迭代器可以激发你改变集合中的元素; the subsequent iterating behaviour would then be undefined. 随后的迭代行为将是未定义的。
Note that the C++ standard says that set<T>::iterator
is const
so the old-fashioned pre C++11 way still wouldn't work. 请注意,C ++标准说set<T>::iterator
是const
所以老式的前C ++ 11方法仍然不起作用。
Adding on nate's answer :添加内特的答案:
A set is like a map with no values, only keys.集合就像 map,没有值,只有键。 Since those keys are used for a tree that accelerates operations on the set, they cannot change.由于这些键用于加速集合操作的树,因此它们不能更改。 Thus all elements must be
const
to keep the constraints of the underlying tree from being broken.因此,所有元素都必须是const
以防止底层树的约束被破坏。
With C++17 there is the new extract
member function, so an alternative to const_cast
could be:对于 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);
}
Probably useful as hot-fix.可能用作热修复。 In general it's hard to see any advantage over a std::map
.一般来说,很难看出比std::map
有任何优势。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.