vector <unique_ptr <a>&gt;使用初始化列表

时间:2017-10-13 19:46:32

标签: c++ c++11 constructor containers unique-ptr

我有一个错误:在编译类似于下面的代码时调用'std :: __ 1 :: unique_ptr&gt;'的隐式删除的复制构造函数 c ++ -std = c ++ 14 unique_ptr_vector.cpp -o main

这是一个简化版本:

头文件'my_header.h':

#include <iostream>
#include <string>
#include <memory>
#include <vector>

class A{
public:
    A() : n(0) {}
    A(int val) : n(val) {} 
    A(const A &rhs): n(rhs.n) {}
    A(A &&rhs) : n(std::move(rhs.n)) {}
    A& operator=(const A &rhs) { n = rhs.n; return *this; }
    A& operator=(A &&rhs) { n = std::move(rhs.n); return *this; }
    ~A() {}

    void print() const { std::cout << "class A: " << n << std::endl; }
private:
    int n;
};

namespace {
    std::vector<std::unique_ptr<A>> vecA = {
        std::make_unique<A>(1),
        std::make_unique<A>(2),
        std::make_unique<A>(3),
        std::make_unique<A>(4)
    };
}

我的src文件'unique_ptr_vector.cpp':

#include "my_header.h"

using namespace std;

int main()
{
    for(const auto &ptrA : vecA){
        ptrA->print();
    }
    return 0;
}

我是否真的需要为每个组件单独使用push_back(std :: make_unique()), 或者在标题中填充容器的首选方法是什么?或者这一般是个坏主意吗?

我看到了this onethis onethis one等问题。

我现在知道初始化列表似乎不可能。但是人们通常会对container<unique_ptr>做些什么。我应该只是避免在标题中初始化...

1 个答案:

答案 0 :(得分:9)

初始化列表是const数组的包装器。

unique_ptr的{​​{1}}无法移动。

我们可以这样(以完全合法的方式)解决这个问题:

const

Live example

使用:

template<class T>
struct movable_il {
  mutable T t;
  operator T() const&& { return std::move(t); }
  movable_il( T&& in ): t(std::move(in)) {}
};

template<class T, class A=std::allocator<T>>
std::vector<T,A> vector_from_il( std::initializer_list< movable_il<T> > il ) {
  std::vector<T,A> r( std::make_move_iterator(il.begin()), std::make_move_iterator(il.end()) );
  return r;
}

如果您想知道为什么初始值设定项列出引用常量数据,您必须追踪和阅读委员会会议记录或询问那里的人。我猜这是关于最少惊喜的原则和/或有关于可变数据和视图类型的bugaboos的人(例如将auto v = vector_from_il<int>({ std::make_unique<int>(7), std::make_unique<int>(3) }); 重命名为array_view)。

如果你想要的不仅仅是矢量:

span

仍需要使用关联容器进行按摩才能正常工作,因为我们还想移动密钥。

template<class C, class T=typename C::value_type>
C container_from_il( std::initializer_list< movable_il<T> > il ) {
  C r( std::make_move_iterator(il.begin()), std::make_move_iterator(il.end()) );
  return r;
}