带有 unique_ptr 的双端队列向量的编译器错误
Posted
技术标签:
【中文标题】带有 unique_ptr 的双端队列向量的编译器错误【英文标题】:Compiler error with vector of deque of unique_ptr 【发布时间】:2016-04-02 00:39:06 【问题描述】:以下代码无法在 gcc 5.3 上编译,并出现编译器错误,抱怨以某种方式调用了 unique_ptr 的复制构造函数。有人可以解释为什么会这样吗?
#include <iostream>
#include <memory>
#include <deque>
using Foo = std::deque<std::unique_ptr<int>>;
void foo()
std::vector<Foo> a;
a.emplace_back(); // this fails to compile
编译器错误的关键行是:
gcc-4.9.2/include/c++/4.9.2/bits/stl_construct.h:75:7: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]’ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...);
【问题讨论】:
哦,是的,这是一团糟。 您应该包括<vector>
和<deque>
,而不是<queue>
。在这里并不重要。
感谢您指出这一点。固定的。顺便说一句,如果我们将 std::deque 替换为 std::queue,则代码无法编译为相同的编译器错误。
@BarryTheHatchet。在问题中添加了错误消息。谢谢!
【参考方案1】:
vector::emplace_back
需要处理重新分配。
在vector
重新分配时,现有元素将被移动,如果有的话
std::is_copy_constructible
确定);或
他们的移动构造函数是noexcept
。
否则它们会被复制。这是为了维护强大的异常安全保障。
std::deque<std::unique_ptr<int>>
的移动构造函数不是 noexcept
(根据实现,可能需要分配内存)。
std::deque<std::unique_ptr<int>>
可以根据std::is_copy_constructible
复制,因为它只检查是否存在具有正确签名的构造函数,而不是该构造函数的主体是否会真正编译。
vector::emplace_back
因此尝试复制它。
编译器崩溃了。
【讨论】:
这可以被认为是语言的缺陷吗?因为这是荒谬的。 @BarryTheHatchet:上次我戳了一下,它与有状态分配器有关。您无法在编译时判断两个分配器是否相等,因此在编译时您不知道是否可以移动或必须复制。 @MooingDuck 那是一个单独的野兽(移动任务)。 @BarryTheHatchet 由于自定义分配器construct
s,我认为很难修复。您不能仅在 is_copy_constructible
等上进行 SFINAE,因为 construct
可以破坏参数。
@T.C.非常感谢!解释很有意义。不得不说这种行为很让人吃惊,推理也很微妙,尤其是deque move构造函数不是noexcept这一点。以上是关于带有 unique_ptr 的双端队列向量的编译器错误的主要内容,如果未能解决你的问题,请参考以下文章