STL 中使用的 Comp 比较器是不是需要从不更改 STL 中的比较对象?
Posted
技术标签:
【中文标题】STL 中使用的 Comp 比较器是不是需要从不更改 STL 中的比较对象?【英文标题】:Is Comp comparator used in STL required to never change compared objects in STL?STL 中使用的 Comp 比较器是否需要从不更改 STL 中的比较对象? 【发布时间】:2018-02-09 12:29:40 【问题描述】:我正在检查使用 std::auto_ptr
的旧代码,我想知道这是否是未定义的行为:
std::vector<std::auto_ptr<int>> v;
//populate v with elements...
std::sort(v.begin(), v.end(), [](auto a, auto b) /* some reasonable "less" comparison */);
现在,这种比较器当然会清空集合,因为std::auto_ptr
的复制构造函数采用非常量引用。我一直在寻找规定这种行为的标准规则,但我能找到的只是:
[alg.sorting#2]比较是一个函数对象类型。 应用于比较类型对象的函数调用操作的返回值,当上下文转换为布尔值时,如果调用的第一个参数小于第二个参数,则返回 true,否则返回 false。 比较 comp 始终用于假设排序关系的算法。 假设 comp 不会通过取消引用的迭代器应用任何非常量函数。
但这至少还不够,因为按值获取两个 std::auto_ptr 的比较器不会“通过取消引用的迭代器应用任何非常量函数”——比较器本身不应用复制构造函数。
此外,同样的问题也适用于Compare
的超类——在关于BinaryPredicate
的[algorithms.requirements#7] 段落中,我们可以读到几乎相同的句子:
binary_pred 不应通过取消引用的迭代器应用任何非常量函数。
这意味着,如果存在问题,将传播到许多其他算法。
我的问题是:比较器是否按值接受 std::auto_ptr
参数,是否违反了 std::sort
的要求,使调用它成为未定义的行为,或者这段代码很好,只是工作错误; )?或者,这可能是 C++ 标准库规范中的问题?
阅读更多:
http://eel.is/c++draft/alg.sorting#2.sentence-4 http://eel.is/c++draft/algorithms.requirements#7.sentence-4 http://www.eel.is/c++draft/sort http://en.cppreference.com/w/cpp/algorithm/sort http://en.cppreference.com/w/cpp/concept/Compare【问题讨论】:
相关:wg21.link/LWG3031 【参考方案1】:这基本上是LWG 3031。
您的比较对象没有违反Compare
应该如何表现的任何规定的先决条件,这是一个标准缺陷。您没有在对象上调用任何非const
操作,而是在调用非const
复制构造函数。这并没有真正涵盖。
然而,这个特殊的例子 是 未定义的行为有一个不同的原因:你的比较,由于它破坏了它的所有元素,将不能成为一个严格的弱顺序 - 这与 @987654322 相冲突@。
【讨论】:
我不完全相信:这样的比较器,如果“合理”,仍然有效。当然,它会修改带下划线的集合,但是对于给定的两个 auto_ptr 值,它会返回规范所要求的值。 @MichałŁoś 你能举一个比return false;
更复杂的“合理”比较器的例子吗?
实际上 - 你所描述的足够合理:D,但你去吧:coliru.stacked-crooked.com/a/ace61f082d999a0a - 请注意,我指出传递给比较的值而不是对象身份。
@MichałŁoś 我不知道您是否可以称其为有效的严格弱命令。因为如果你有auto_ptr<int> a(new int(1)), b(new int(2)), c(new int(3));
,你就会有compare(a,b)
和compare(b,c)
(b
现在是空的),然后是!compare(a,c)
。
我完全同意这一点,但标准中使用的表示法的意图不是处理“a”和“b”值而不是实际对象吗?例如:eel.is/c++draft/alg.sorting#4.1。至少我是这么理解的。以上是关于STL 中使用的 Comp 比较器是不是需要从不更改 STL 中的比较对象?的主要内容,如果未能解决你的问题,请参考以下文章