2014-12-27 63 views
4

我正在使用STL关联容器(std::setstd::map)以及包含std::unique_ptr<>实例的键。主要定义等效于以下:STL关联容器:清除并获取(不可复制)元素

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; 
} 
+3

_“是否有非UB方式来解决这个问题?”_编号[N3645](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3645 .pdf)可能会有所帮助,但该提案已被拒绝,并且未被再次提交。 – 2014-12-27 21:09:54

回答

6

这就是其中之一:

实在不好意思。我们试图做这个工作,并不能通过 委员会。

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才能实现它。它没有被重新提交。

+0

感谢您的回答。 如果我设法做一些异常安全*(RAII式迭代器“橡皮擦”可能?)*,它会保持UB吗? – intelfx 2014-12-27 21:22:51

+0

还有一个后续问题。该提案(后者)的地位如何?被拒绝,还是未被审查,或被拒绝并将被重新提交?.. – intelfx 2014-12-27 21:25:37

+1

将'const'抛出去并不是UB。试图修改一个'const'对象是UB。 – Columbo 2014-12-27 21:41:14