【问题标题】:STL associative containers: erasing and getting back the (noncopyable) elementSTL 关联容器:擦除和取回(不可复制的)元素
【发布时间】:2014-12-27 20:44:15
【问题描述】:

我正在使用带有 std::unique_ptr<> 实例的键的 STL 关联容器(std::setstd::map)。键定义等价于:

struct Key
{
    std::unique_ptr<Object> object;
    bool operator== (const Key& rhs) const { return object->equal (*rhs.object); }
    bool operator<  (const Key& rhs) const { return object->less (*rhs.object); }
}

众所周知,STL 关联容器(尤其是自 C++11 起)无法获得对要从中移动的键的非常量引用。而且我的密钥是不可复制的,所以c++: Remove element from container and get it back 不起作用。

有没有非 UB 方法来解决这个问题?

我目前的解决方案如下:

template <typename T>
using map_pair_type = std::pair<typename T::key_type, typename T::mapped_type>;

template <typename T>
typename T::value_type take_set (T& container, typename T::iterator iterator)
{
    typename T::value_type result = std::move (const_cast<typename T::value_type&> (*iterator));
    container.erase (iterator);
    return result;
}

template <typename T>
map_pair_type<T> take_map (T& container, typename T::iterator iterator)
{
    map_pair_type<T> result {
        std::move (const_cast<typename T::key_type&> (iterator->first)),
        std::move (iterator->second)
    };
    container.erase (iterator);
    return result;
}

【问题讨论】:

  • “有没有非 UB 的方法来解决这个问题?” 没有。N3645 可能会有所帮助,但该提案被拒绝并且没有被重新再次提交。

标签: c++ templates c++11 stl


【解决方案1】:

这是其中之一:

真的很抱歉。我们试图完成这项工作,但无法通过 委员会。

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3586.pdf

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3645.pdf

据我所知,您的解决方案是最好的。您的地图解决方案确实表现出未定义的行为。如果第二步引发异常,情况将变得非常糟糕。除此之外,我怀疑它会起作用。而且我怀疑我会因为这样说而被否决。

UB 的原因是密钥被定义为const(而不是仅仅被 const 引用引用)。在那种情况下抛弃const(并让移动构造函数修改对象)是UB。

如果 N3586 被接受,您可以:

move_only_type mot = move(*s.remove(s.begin()));

或:

move_only_key mok = move(m.remove(m.begin())->first);

N3586/N3645 在委员会中表现出色。它经过讨论并通过了工作组阶段,但在全体委员会中被否决。担心的是 std::lib 必须提交 UB 才能实现它。尚未重新提交。

更新

现在可以在 C++17 中执行此操作,但成员函数称为 extract 而不是 remove

【讨论】:

  • 感谢您的回答。如果我设法在异常安全的情况下做某事(可能是 RAII 样式的迭代器“橡皮擦”?),它会保持 UB 吗?
  • 还有一个后续问题。该提案(后者)的状态如何?是被拒绝了,还是尚未审核,还是被拒绝并将重新提交?..
  • 抛弃const 绝不是UB。尝试修改 const 对象是 UB。
  • @Columbo:从一个对象移动不算修改它?你是对的,因为这个答案的措辞可以说在这方面有点误导。
  • 公平点。我试图让答案更准确。
猜你喜欢
  • 2013-04-07
  • 1970-01-01
  • 2015-06-06
  • 1970-01-01
  • 2013-04-08
  • 2016-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多