【发布时间】:2021-02-19 19:12:33
【问题描述】:
如果自定义比较器在重新平衡期间抛出异常,std::map 会做什么?显然,它应该记住所有先前的回合并将所有内容恢复到原始状态。是真的吗?
【问题讨论】:
-
这在 CPPCON 的一次演讲中有所体现。现在找不到,等我回家再找。
标签: c++ dictionary stdmap exception-safety
如果自定义比较器在重新平衡期间抛出异常,std::map 会做什么?显然,它应该记住所有先前的回合并将所有内容恢复到原始状态。是真的吗?
【问题讨论】:
标签: c++ dictionary stdmap exception-safety
参见[associative.reqmts.except]:
对于关联容器,没有
clear()函数会引发异常。erase(k)不会抛出异常,除非该异常是由容器的Compare对象(如果有)抛出的。对于关联容器,如果
insert或emplace函数中插入单个元素的任何操作引发异常,则插入无效。对于关联容器,
swap函数不会引发异常,除非该异常是由容器的Compare对象(如果有)的交换引发的。
所以你基本上是对的(在单个元素插入的情况下),但这并不意味着容器必须“记住所有先前的轮次”才能“将所有内容恢复到其原始状态”。假设关联容器是使用自平衡二叉搜索树实现的(我不确定是否还有其他可能性),比较只是为了沿着树向下查找必须插入新节点的位置.如果在此过程中通过异常退出比较,则树还没有被修改,所以容器所要做的就是释放它此时为新元素分配的内存(如果有的话)。接下来的重新平衡步骤不会产生异常,因为它仅涉及执行一堆树旋转和更新内部簿记数据,例如节点是红色还是黑色。
【讨论】:
erase(k) 抛出异常,它不会说明容器处于什么状态。密钥是否被移除?