std :: map<> ::使用不可复制的对象和统一初始化插入

时间:2013-02-16 23:51:08

标签: c++ c++11 noncopyable movable

查看以下代码:

#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构建的{{1}}?两者都不应该产生可以成功移入地图的右值吗?

2 个答案:

答案 0 :(得分:18)

[这是完全重写。我之前的回答与问题无关。]

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()}));

现在list-initializer知道查找map_type::value_type构造函数,找到相关的可移动构造函数,结果是一个rvalue对,它绑定P&& - insert的重载功能

(另一种选择是将emplace()piecewise_constructforward_as_tuple一起使用,但这会更加冗长。)

我认为这里的道德是list-initializers寻找可行的重载 - 但是他们必须知道要寻找什么!

答案 1 :(得分:0)

除了提供移动(赋值)构造函数的其他答案之外,您还可以通过指针(尤其是unique_ptr)存储不可复制的对象。 unique_ptr将为您处理资源转移。