提问人:Mikhail Shatalin 提问时间:6/5/2018 最后编辑:M.MMikhail Shatalin 更新时间:6/5/2018 访问量:687
C++ 如何将unique_ptr队列添加到向量中
C++ How to add queue of unique_ptr's to a vector
问:
简化代码:
#include <queue>
#include <memory>
#include <vector>
class Foo {
public:
Foo() {};
virtual ~Foo() {}
};
int main()
{
std::queue<std::unique_ptr<Foo>> queue;
auto element = std::make_unique<Foo>();
queue.push(std::move(element));
std::vector<std::queue<std::unique_ptr<Foo>>> vector;
// Error 1
vector.push_back(queue);
// Error 2
vector.push_back(std::move(queue));
// Error 3
vector.push_back({});
return 0;
}
错误:
'std::unique_ptr>::unique_ptr(const std::unique_ptr<_Ty,std::d efault_delete<_Ty>> &)':尝试 引用已删除的函数
显然,复制 unique_ptr 的 c~tor 被删除了,但我不是要复制它。我是吗?
答:
这有点棘手。如果以下两种情况之一为真,则所有可以增加向量大小的函数都必须以异常安全的方式执行:std::vector<T>
T
有一个移动构造函数,可以保证它永远不会抛出任何异常;或T
具有复制构造函数。
因此,在大多数实现中,如果声明了移动构造函数或等效函数,则将使用移动构造函数进行这些操作。如果没有,并且具有复制构造函数,则将使用复制构造函数,即使具有移动构造函数也是如此。T
nothrow
vector
T
T
vector
T
这里的问题是,它总是声明它有一个复制构造函数,即使该复制构造函数实际上不能实例化,并且总是声明它有一个可能会抛出的移动构造函数,即使容器成员的移动构造函数保证它不会抛出。std::queue
该标准在 [queue.defn] 中将这些指定为:
namespace std {
template<class T, class Container = deque<T>>
class queue {
// ...
public:
explicit queue(const Container&);
explicit queue(Container&& = Container());
// ...
};
}
可以通过几种方式改进此类模板定义,使其更加“SFINAE”,并避免遇到类似问题。(也许有人可以检查其他有类似问题的类,并向图书馆工作组提交提案。
将移动构造函数更改为承诺在类型做出相同承诺时不抛出,通常使用如下语言完成:
Container
explicit queue(Container&& rhs = Container()) nothrow(see below);
言论:里面的表达式等效于 。
noexcept
is_nothrow_move_constructible_v<Container>
如果类型不可复制,则更改要删除的复制构造函数,通常使用以下语言完成:
Container
explicit queue(const Container&);
言论:此构造函数应定义为已删除,除非是 。
is_copy_constructible_v<Container>
true
评论
deque
queue
noexcept
deque
vector
queue< unique_ptr<Foo>, vector<unique_ptr<Foo>> >
deque
queue
评论
push_back
emplace_back
std::queue
std::vector
std::deque
move
deque
deque
vector
noexcept
vector