修改 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::setconst_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>::constructT * 传递给它,导致构建 T,而不是 const T

我认为这意味着 std::set<T> 不允许将其元素定义为 const,并且由于没有任何其他禁令,意味着允许通过 const_cast 修改元素。


就我个人而言,如果我找不到更好的选择,我会考虑通过将整个东西放在一个包装器结构中来避免这个问题,它定义了一个成员 mutable X x;。这将允许在没有 const_cast 的情况下进行修改,只要您注意避免更改集合中已有元素的相对顺序即可。它还可以作为您的代码的其他读者的文档,说明您的集合的元素可以并且将会被修改。