给出以下代码:
#include <set>
struct X {
int a, b;
friend bool operator<(X const& lhs, X const& rhs) {
return lhs.a < rhs.a;
}
};
int main() {
std::set<X> xs;
// some insertion...
auto it = xs.find({0, 0}); // assume it != xs.end()
const_cast<X&>(*it).b = 4; // (1)
}
(1)
是否定义了行为?即,我是否允许const_cast
引用从const_iterator
std::set
获取的元素,如果修改不改变顺序,则修改它?
我已经阅读了一些帖子,提出了这种const_cast
,但我想知道这是否是实际定义的行为。
答案 0 :(得分:2)
这是否已定义行为尚不清楚,但我相信确实如此。
在std::set
关于修改值的描述中似乎没有明确的禁止,除了你已经暗示的限制,比较器在传递相同的输入时必须返回相同的结果([associative.reqmts] ] P3)。
但是,修改定义为const
的对象的一般规则确实适用。是否set
将其元素定义为const
是不明确的。如果是,则不允许修改元素([dcl.type.cv] p4)。
但是[container.requirements.general] p3读取:
对于受本子条款影响的声明
allocator_type
的组件,存储在这些组件中的对象应使用allocator_traits<allocator_type>::construct
函数构造, 使用allocator_traits<allocator_type>::destroy
函数(20.7.8.2)销毁。
std::set<T>
声明allocator_type
,默认为std::allocator<T>
。 std::allocator_traits<allocator_type>::construct
将T *
传递给T
,导致构建const T
,而不是std::set<T>
。
我认为这意味着const
不允许将其元素定义为const_cast
,并且由于没有任何其他禁止,意味着允许通过mutable X x;
修改元素。
就个人而言,如果我找不到更好的选择,我会考虑通过将整个事物放在一个定义成员const_cast
的包装器结构中来避免这个问题。这将允许在没有{{1}}的情况下进行修改,只要您注意避免更改集合中已有元素的相对顺序即可。它还可以作为代码的其他读者的文档,可以修改集合的元素。