向量<unique_ptr<A>>使用初始化列表
我遇到了一个错误:在编译类似于下面的代码时调用'std::__1::unique_ptr >'的隐式删除的复制构造函数c++ -std=c++14 unique_ptr_vector.cpp -o main
这是一个简化版:
头文件'my_header.h':
header file '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<A>(<some_number>))
,或者在标题中填充容器的首选方法是什么?还是一般来说这是个坏主意?
Do I really need to use push_back(std::make_unique<A>(<some_number>))
individually for each component,
Or what would be a preferred way to populate a container in a header? Or is this a bad idea in general?
我看到了类似 这个,这个和 这个.
I have seen problems around like this one, this one, and this one.
我现在知道初始化列表似乎是不可能的.但是人们通常用 container<unique_ptr>
做什么.我是否应该简单地避免在标题中初始化它...
I know now Initialization list seems impossible. but what do people normally do with container<unique_ptr>
. Should I just simply avoid initialize that in a header...
推荐答案
初始化列表是 const
数组的包装器.
Initialization lists are wrappers around const
arrays.
unique_ptr
s 是 const
不能被移出.
unique_ptr
s that are const
cannot be moved-from.
我们可以像这样(以完全合法的方式)解决这个问题:
We can hack around this (in a perfectly legal way) like this:
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;
}
活生生的例子.
用途:
auto v = vector_from_il< std::unique_ptr<int> >({
std::make_unique<int>(7),
std::make_unique<int>(3)
});
如果您想知道为什么初始化程序列表引用 const 数据,您必须追踪并阅读委员会会议记录或询问在场的人.我猜这是关于最小惊喜的原则和/或人们对可变数据和视图类型的错误(例如将 array_view
重命名为 span
).
If you want to know why initializer lists reference const data, you'll have to track down and read committee minutes or ask someone who was there. I'd guess it is about the principle of least surprise and/or people with bugaboos about mutable data and view types (such as the renaming of array_view
to span
).
如果您想要的不仅仅是向量:
If you want more than just vectors:
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;
}
这仍然需要按摩才能与关联容器一起正常工作,因为我们还想移动键.
which still needs massaging to work right with associative containers as we also want to move the key.
template<class VT>
struct fix_vt {
using type=VT;
};
template<class VT>
using fix_vt_t = typename fix_vt<VT>::type;
template<class VT>
struct fix_vt<const VT>:fix_vt<VT>{};
template<class K, class V>
struct fix_vt<std::pair<K,V>>{
using type=std::pair<
typename std::remove_cv<K>::type,
typename std::remove_cv<V>::type
>;
};
template<class C, class T=fix_vt_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;
}
相关文章