带有 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&lt;_Tp, _Dp&gt;::unique_ptr(const std::unique_ptr&lt;_Tp, _Dp&gt;&amp;) [with _Tp = int; _Dp = std::default_delete&lt;int&gt;]’ ::new(static_cast&lt;void*&gt;(__p)) _T1(std::forward&lt;_Args&gt;(__args)...);

【问题讨论】:

哦,是的,这是一团糟。 您应该包括&lt;vector&gt;&lt;deque&gt;,而不是&lt;queue&gt;。在这里并不重要。 感谢您指出这一点。固定的。顺便说一句,如果我们将 std::deque 替换为 std::queue,则代码无法编译为相同的编译器错误。 @BarryTheHatchet。在问题中添加了错误消息。谢谢! 【参考方案1】: vector::emplace_back 需要处理重新分配。

vector 重新分配时,现有元素将被移动,如果有的话

它们不能被复制(由std::is_copy_constructible确定);或 他们的移动构造函数是noexcept

否则它们会被复制。这是为了维护强大的异常安全保障。

std::deque&lt;std::unique_ptr&lt;int&gt;&gt; 的移动构造函数不是 noexcept(根据实现,可能需要分配内存)。 std::deque&lt;std::unique_ptr&lt;int&gt;&gt; 可以根据std::is_copy_constructible 复制,因为它只检查是否存在具有正确签名的构造函数,而不是该构造函数的主体是否会真正编译。 vector::emplace_back 因此尝试复制它。 编译器崩溃了。

【讨论】:

这可以被认为是语言的缺陷吗?因为这是荒谬的。 @BarryTheHatchet:上次我戳了一下,它与有状态分配器有关。您无法在编译时判断两个分配器是否相等,因此在编译时您不知道是否可以移动或必须复制。 @MooingDuck 那是一个单独的野兽(移动任务)。 @BarryTheHatchet 由于自定义分配器constructs,我认为很难修复。您不能仅在 is_copy_constructible 等上进行 SFINAE,因为 construct 可以破坏参数。 @T.C.非常感谢!解释很有意义。不得不说这种行为很让人吃惊,推理也很微妙,尤其是deque move构造函数不是noexcept这一点。

以上是关于带有 unique_ptr 的双端队列向量的编译器错误的主要内容,如果未能解决你的问题,请参考以下文章

如何在其中构造一个带有成员函数的双端队列类? C++

STL中的双端队列

STL 中的双端队列到底是啥?

检查数组是不是在数组的双端队列中? Python

基于双向链表的双端队列

java中的双端队列及使用