c++ 复制/移动/交换是否也在std::set/map的比较器上操作?

kiz8lqtg  于 2023-02-01  发布在  其他
关注(0)|答案(3)|浏览(135)

移动赋值、复制赋值和交换操作(如果有)中的哪一个也对集合和Map的嵌入式比较器进行操作?
(In换句话说,如果I例如swap两个set,它们的比较器是否也会交换?)
如果答案与C的旧版本不同(例如C98或C ++03),请注明。

8xiog9wr

8xiog9wr1#

标准包含以下保证
对于关联容器,交换函数不会抛出异常,除非该异常是由容器的Compare对象(如果有的话)的交换抛出的。
所以答案是肯定的--比较对象也会被交换函数交换。
这个报价是针对C++11-17的。我没有更早的草稿。
对于复制和移动-我只能推断-因为任何合理的复制/移动实现都使用交换,所以同样的答案是正确的。但我没有找到具体的引用...

laik7k3q

laik7k3q2#

引用n1905(这是我能找到的最接近2003年官方出版物的一个版本,尽管它是后来的),在一般容器要求下:
[自由容器要求]/11:
除非另有规定,本条款中定义的所有容器类型均符合以下附加要求:

  • swap()函数不会抛出异常,除非该异常是由容器的Compare对象的复制构造函数或赋值运算符抛出的

因此,如果一个Compare对象需要复制,这几乎指定了它应该被复制。

irlmq6kh

irlmq6kh3#

这是LWG 2227,目前仍处于打开状态。
现行标准对相关要求尚不十分明确。
交换相对简单。主要的实现(libstdc++、libc和微软的STL)都交换swap中的比较对象。这也与其他建议交换比较对象的措辞一致。
主要的实现在移动上仍然存在分歧。正如我今天所检查的,libstdc
和微软的STL的当前实现都复制了底层树/哈希表的move构造函数中的比较对象,但libc只是分别移动它。注意,与2015年的评论相比,微软的实现情况发生了变化。
然而,比较对象/哈希器/ predicate 的可复制构造要求显然没有消失,也就是说,你可能会认为它仍然像C
98/03时代一样,根本没有移动。
逻辑上libstdc++/MS STL的行为更简单,比较对象的行为类似于迭代器或普通函数对象(但不是在转发调用 Package 器中传递的函数):期望通过值传递,并且不能明确暗示这些对象上的标识。这在逻辑上与旧世界一致,没有移动。
然而,对于实现来说,分别移动可能会简单一些,通过使用默认的特殊成员函数重用一些EBO帮助对象(例如libc中的__compressed_pair)的移动操作,而不是用户定义的复制(不移动)。这样的实现可能需要额外关注异常规范,但在这些支持分配器的容器上支持分配器传播已经很复杂了。
不过,有状态比较对象(以及哈希器/ predicate )在C
容器中没有得到一流的支持,而且可悲的是,如何在不扰乱客户端代码中的所有权管理的情况下支持它们并不明显,因为用户 * 需要 * 将状态保存在其他地方,而这些状态并不是自然的由容器对象(唯一地)拥有,特别是当考虑相反的情况时,只需添加一些std::ref。这并不比有状态分配器更糟糕(这会带来另一个复杂性维度,比如对分配器传播的细粒度控制以及在swap上使用UB ping容器对象中的不等分配器)。

相关问题