我正在使用STL关联容器(std::set
和std::map
)以及包含std::unique_ptr<>
实例的键。关键定义等同于以下内容:
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以来)无法获得对要移动的键的非const引用。我的密钥是不可复制的,因此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;
}
答案 0 :(得分:7)
这是其中之一:
真的很抱歉。我们试图让这项工作无法完成 委员会。
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
。