给定以下代码:
#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
对从 std::set
的 const_iterator
获取的元素的引用,并在修改完成时修改它不改变顺序?
我在这里和那里阅读了一些提出这种 const_cast
的帖子,但我想知道这是否是实际定义的行为。
最佳答案
这是否定义了行为尚不清楚,但我相信是的。
在std::set
的描述中似乎没有具体禁止。关于修改值,除了您已经暗示的限制外,比较器在传递相同的输入时必须返回相同的结果 ([associative.reqmts]p3)。
但是,修改对象的一般规则定义为 const
确实适用。是否set
将其元素定义为 const
没有拼写出来。如果是,则不允许修改元素 ([dcl.type.cv]p4)。
但是 [container.requirements.general]p3 显示:
For the components affected by this subclause that declare an
allocator_type
, objects stored in these components shall be constructed using theallocator_traits<allocator_type>::construct
function and destroyed using theallocator_traits<allocator_type>::destroy
function (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
的情况下进行修改,只要您注意避免更改集合中已有元素的相对顺序即可。它还可以作为您的代码的其他读者的文档,说明您的集合的元素可以并且将会被修改。
关于c++ - 修改 std::set 的元素 - 定义的行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43340050/