修改 std::set 的元素 - 定义的行为?
Modification of elements of std::set - Defined behavior?
给定以下代码:
#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
的描述中似乎没有具体禁止修改值,除了您已经暗示的限制,比较器必须 return 在传递相同的结果时得到相同的结果输入 ([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 the allocator_traits<allocator_type>::construct
function and
destroyed using the allocator_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
的情况下进行修改,只要您注意避免更改集合中已有元素的相对顺序即可。它还可以作为您的代码的其他读者的文档,说明您的集合的元素可以并且将会被修改。
给定以下代码:
#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
的描述中似乎没有具体禁止修改值,除了您已经暗示的限制,比较器必须 return 在传递相同的结果时得到相同的结果输入 ([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
的情况下进行修改,只要您注意避免更改集合中已有元素的相对顺序即可。它还可以作为您的代码的其他读者的文档,说明您的集合的元素可以并且将会被修改。