-->

的std ::地图<> ::使用不可复制的对象和均匀的初始化插入(std::map<

2019-07-20 01:02发布

看看下面的代码:

#include <utility>
#include <map>

// non-copyable but movable
struct non_copyable {
    non_copyable() = default;

    non_copyable(non_copyable&&) = default;
    non_copyable& operator=(non_copyable&&) = default;

    // you shall not copy
    non_copyable(const non_copyable&) = delete;
    non_copyable& operator=(const non_copyable&) = delete;
};

int main() {
    std::map<int, non_copyable> map;
    //map.insert({ 1, non_copyable() });  < FAILS
    map.insert(std::make_pair(1, non_copyable()));
    // ^ same and works
}

编译此片段在取消对于g ++ 4.7标记行时失败。 产生的错误指示non_copyable不能被复制,但我预期移动。

为什么插入std::pair使用统一初始化失败,但不使用一个构造构造std::make_pair ? 两者不应该产生可成功移动到地图的右值?

Answer 1:

[这是一个完全重写。 我刚才的答复无关的问题。]

map有两个相关的insert重载:

  • insert(const value_type& value) ,并

  • <template typename P> insert(P&& value)

当您使用简单的列表,初始化map.insert({1, non_copyable()}); ,所有可能的过载被考虑。 但只有第一个(在一个以const value_type&被发现,因为其他没有任何意义(没有办法奇迹般地猜测你的意思是创建一个对)。 因为你的元素是不可拷贝的第一个重载没有当然的工作。

您可以通过显式地创建一对使第二超负荷的工作,无论是与make_pair ,因为你已经描述的,或通过显式命名值类型:

typedef std::map<int, non_copyable> map_type;

map_type m;
m.insert(map_type::value_type({1, non_copyable()}));

现在列表初始化知道如何寻找map_type::value_type构造,发现相关的活动之一,其结果是右值对结合到P&&中的-过载insert功能。

(另一种选择是使用emplace()piecewise_constructforward_as_tuple ,尽管这会得到很多更详细。)

我想,这里的寓意是,列表初始化寻找可行的重载 - 但他们必须知道要寻找什么!



Answer 2:

除了提供移动(分配)构造的其他的答案,你也可以通过指针存储不可复制的对象,尤其是unique_ptrunique_ptr会为你处理资源的运动。



文章来源: std::map<>::insert using non-copyable objects and uniform initialization