【问题标题】:Moving std::list<std::unique_ptr> into vector attempts to reference a deleted function将 std::list<std::unique_ptr> 移入向量尝试引用已删除的函数
【发布时间】:2017-08-31 07:30:16
【问题描述】:

这是一个完整的程序,可以重现我的问题。

#include <vector>
#include <list>
#include <memory>
#include <utility>

int main()
{
    std::vector<std::list<std::unique_ptr<int>>> v;

    std::list<std::unique_ptr<int>> l;
    l.push_back(std::make_unique<int>(0));
    l.push_back(std::make_unique<int>(1));

    v.push_back(std::move(l)); // error
}

在最后一行,编译器抱怨 std::unique_ptrdeleted 复制构造函数被引用。

由于我将列表移动到向量中,我假设不会对列表的元素调用任何复制构造函数。

为什么会这样?我将如何解决它?

我正在使用 MSVC 2017。

live example on godbolt

错误全文:

example.cpp
/opt/compiler-explorer/windows/19.10.25017/lib/native/include/xmemory0(840): error C2280: 'std::unique_ptr<int,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': attempting to reference a deleted function
        with
        [
            _Ty=int
        ]
/opt/compiler-explorer/windows/19.10.25017/lib/native/include/memory(1857): note: see declaration of 'std::unique_ptr<int,std::default_delete<_Ty>>::unique_ptr'
        with
        [
            _Ty=int
        ]
/opt/compiler-explorer/windows/19.10.25017/lib/native/include/xmemory0(959): note: see reference to function template instantiation 'void std::allocator<_Other>::construct<_Objty,const std::unique_ptr<int,std::default_delete<_Ty>>&>(_Objty *,const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' being compiled
        with
        [
            _Other=std::_List_node<std::unique_ptr<int,std::default_delete<int>>,void *>,
            _Objty=std::unique_ptr<int,std::default_delete<int>>,
            _Ty=int
        ]
/opt/compiler-explorer/windows/19.10.25017/lib/native/include/xmemory0(959): note: see reference to function template instantiation 'void std::allocator<_Other>::construct<_Objty,const std::unique_ptr<int,std::default_delete<_Ty>>&>(_Objty *,const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' being compiled
        with
        [
            _Other=std::_List_node<std::unique_ptr<int,std::default_delete<int>>,void *>,
            _Objty=std::unique_ptr<int,std::default_delete<int>>,
            _Ty=int
        ]
/opt/compiler-explorer/windows/19.10.25017/lib/native/include/xmemory0(1097): note: see reference to function template instantiation 'void std::allocator_traits<_Alloc>::construct<_Ty,const std::unique_ptr<int,std::default_delete<int>>&>(std::allocator<_Other> &,_Objty *,const std::unique_ptr<int,std::default_delete<int>> &)' being compiled
        with
        [
            _Alloc=std::allocator<std::_List_node<std::unique_ptr<int,std::default_delete<int>>,void *>>,
            _Ty=std::unique_ptr<int,std::default_delete<int>>,
            _Other=std::_List_node<std::unique_ptr<int,std::default_delete<int>>,void *>,
            _Objty=std::unique_ptr<int,std::default_delete<int>>
        ]
/opt/compiler-explorer/windows/19.10.25017/lib/native/include/xmemory0(1096): note: see reference to function template instantiation 'void std::allocator_traits<_Alloc>::construct<_Ty,const std::unique_ptr<int,std::default_delete<int>>&>(std::allocator<_Other> &,_Objty *,const std::unique_ptr<int,std::default_delete<int>> &)' being compiled
        with
        [
            _Alloc=std::allocator<std::_List_node<std::unique_ptr<int,std::default_delete<int>>,void *>>,
            _Ty=std::unique_ptr<int,std::default_delete<int>>,
            _Other=std::_List_node<std::unique_ptr<int,std::default_delete<int>>,void *>,
            _Objty=std::unique_ptr<int,std::default_delete<int>>
        ]
/opt/compiler-explorer/windows/19.10.25017/lib/native/include/list(853): note: see reference to function template instantiation 'void std::_Wrap_alloc<std::allocator<_Other>>::construct<_Ty,const std::unique_ptr<int,std::default_delete<int>>&>(_Ty *,const std::unique_ptr<int,std::default_delete<int>> &)' being compiled
        with
        [
            _Other=std::_List_node<std::unique_ptr<int,std::default_delete<int>>,void *>,
            _Ty=std::unique_ptr<int,std::default_delete<int>>
        ]
/opt/compiler-explorer/windows/19.10.25017/lib/native/include/list(851): note: see reference to function template instantiation 'void std::_Wrap_alloc<std::allocator<_Other>>::construct<_Ty,const std::unique_ptr<int,std::default_delete<int>>&>(_Ty *,const std::unique_ptr<int,std::default_delete<int>> &)' being compiled
        with
        [
            _Other=std::_List_node<std::unique_ptr<int,std::default_delete<int>>,void *>,
            _Ty=std::unique_ptr<int,std::default_delete<int>>
        ]
/opt/compiler-explorer/windows/19.10.25017/lib/native/include/list(1086): note: see reference to function template instantiation 'std::_List_node<std::unique_ptr<int,std::default_delete<_Ty>>,void *> *std::_List_buy<std::unique_ptr<_Ty,std::default_delete<_Ty>>,_Alloc>::_Buynode<const std::unique_ptr<_Ty,std::default_delete<_Ty>>&>(std::_List_node<std::unique_ptr<_Ty,std::default_delete<_Ty>>,void *> *,std::_List_node<std::unique_ptr<_Ty,std::default_delete<_Ty>>,void *> *,const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' being compiled
        with
        [
            _Ty=int,
            _Alloc=std::allocator<std::unique_ptr<int,std::default_delete<int>>>
        ]
/opt/compiler-explorer/windows/19.10.25017/lib/native/include/list(1085): note: see reference to function template instantiation 'std::_List_node<std::unique_ptr<int,std::default_delete<_Ty>>,void *> *std::_List_buy<std::unique_ptr<_Ty,std::default_delete<_Ty>>,_Alloc>::_Buynode<const std::unique_ptr<_Ty,std::default_delete<_Ty>>&>(std::_List_node<std::unique_ptr<_Ty,std::default_delete<_Ty>>,void *> *,std::_List_node<std::unique_ptr<_Ty,std::default_delete<_Ty>>,void *> *,const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' being compiled
        with
        [
            _Ty=int,
            _Alloc=std::allocator<std::unique_ptr<int,std::default_delete<int>>>
        ]
/opt/compiler-explorer/windows/19.10.25017/lib/native/include/list(1463): note: see reference to function template instantiation 'void std::list<std::unique_ptr<int,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>::_Insert<const std::unique_ptr<_Ty,std::default_delete<_Ty>>&>(std::_List_unchecked_const_iterator<std::_List_val<std::_List_simple_types<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>,std::_Iterator_base0>,const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' being compiled
        with
        [
            _Ty=int
        ]
/opt/compiler-explorer/windows/19.10.25017/lib/native/include/list(1463): note: see reference to function template instantiation 'void std::list<std::unique_ptr<int,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>::_Insert<const std::unique_ptr<_Ty,std::default_delete<_Ty>>&>(std::_List_unchecked_const_iterator<std::_List_val<std::_List_simple_types<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>,std::_Iterator_base0>,const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' being compiled
        with
        [
            _Ty=int
        ]
/opt/compiler-explorer/windows/19.10.25017/lib/native/include/list(1423): note: see reference to function template instantiation 'void std::list<std::unique_ptr<int,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>::_Insert_range<_Iter>(std::_List_unchecked_const_iterator<std::_List_val<std::_List_simple_types<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>,std::_Iterator_base0>,_Iter,_Iter,std::forward_iterator_tag)' being compiled
        with
        [
            _Ty=int,
            _Iter=std::_List_const_iterator<std::_List_val<std::_List_simple_types<std::unique_ptr<int,std::default_delete<int>>>>>
        ]
/opt/compiler-explorer/windows/19.10.25017/lib/native/include/list(1422): note: see reference to function template instantiation 'void std::list<std::unique_ptr<int,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>::_Insert_range<_Iter>(std::_List_unchecked_const_iterator<std::_List_val<std::_List_simple_types<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>,std::_Iterator_base0>,_Iter,_Iter,std::forward_iterator_tag)' being compiled
        with
        [
            _Ty=int,
            _Iter=std::_List_const_iterator<std::_List_val<std::_List_simple_types<std::unique_ptr<int,std::default_delete<int>>>>>
        ]
/opt/compiler-explorer/windows/19.10.25017/lib/native/include/list(939): note: see reference to function template instantiation 'std::_List_iterator<std::_List_val<std::_List_simple_types<std::unique_ptr<int,std::default_delete<_Ty>>>>> std::list<std::unique_ptr<_Ty,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>::insert<std::_List_const_iterator<std::_List_val<std::_List_simple_types<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>>>(std::_List_const_iterator<std::_List_val<std::_List_simple_types<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>>,_Iter,_Iter)' being compiled
        with
        [
            _Ty=int,
            _Iter=std::_List_const_iterator<std::_List_val<std::_List_simple_types<std::unique_ptr<int,std::default_delete<int>>>>>
        ]
/opt/compiler-explorer/windows/19.10.25017/lib/native/include/list(939): note: see reference to function template instantiation 'std::_List_iterator<std::_List_val<std::_List_simple_types<std::unique_ptr<int,std::default_delete<_Ty>>>>> std::list<std::unique_ptr<_Ty,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>::insert<std::_List_const_iterator<std::_List_val<std::_List_simple_types<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>>>(std::_List_const_iterator<std::_List_val<std::_List_simple_types<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>>,_Iter,_Iter)' being compiled
        with
        [
            _Ty=int,
            _Iter=std::_List_const_iterator<std::_List_val<std::_List_simple_types<std::unique_ptr<int,std::default_delete<int>>>>>
        ]
/opt/compiler-explorer/windows/19.10.25017/lib/native/include/list(935): note: while compiling class template member function 'std::list<std::unique_ptr<int,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>::list(const std::list<std::unique_ptr<_Ty,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>> &)'
        with
        [
            _Ty=int
        ]
/opt/compiler-explorer/windows/19.10.25017/lib/native/include/xmemory0(840): note: see reference to function template instantiation 'std::list<std::unique_ptr<int,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>::list(const std::list<std::unique_ptr<_Ty,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>> &)' being compiled
        with
        [
            _Ty=int
        ]
<source>(10): note: see reference to class template instantiation 'std::list<std::unique_ptr<int,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>' being compiled
        with
        [
            _Ty=int
        ]
/opt/compiler-explorer/windows/19.10.25017/lib/native/include/memory(1857): note: 'std::unique_ptr<int,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': function was explicitly deleted
        with
        [
            _Ty=int
        ]
Microsoft (R) C/C++ Optimizing Compiler Version 19.10.25017 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.
Compiler exited with result code 2

【问题讨论】:

  • fyi g++ 5.1.0 编译它没有问题,MSVC 2017 复制了语言标准设置为 ISO C++14 标准 (/std:c++14)
  • 无法使用 gcc 或 clang 重现 - 这可能是 MSVC 缺陷。
  • 这个很基础,但是你确定你的项目中启用了C++11编译模式吗?
  • 我将“最新”更新为“2017”,这样未来的读者就不会感到困惑了。如有错误请指正。
  • 向 MSVC 提交错误报告。

标签: c++ c++11 visual-c++


【解决方案1】:

由于我将列表移动到向量中,我假设不会对列表的元素调用任何复制构造函数。

std::list的移动构造函数不是noexcept[list.overview]),所以std::vector需要调用它的拷贝构造函数,以提供强异常保证。 std::list 的复制构造函数(不出所料)调用列表元素的复制构造函数。

显然,libstdc++ 将std::list 的移动构造函数声明为noexcept,这是标准允许但不要求的。 ([res.on.exception.handling]/5)

【讨论】:

  • 基本上你是说没有办法拥有vector&lt;list&lt;unique_ptr&gt;&gt;list 的移动构造函数可以像交换两个指针一样简单。
  • @DeiDei:我相信这个问题的根本原因是 MSVC 为空的std::list 分配内存,这可能会抛出。您可以通过调试一个除了创建一个空的std::list&lt;int&gt; 之外什么都不做的程序来很好地观察到这一点。进入构造函数,看看_List_alloc() 中发生了什么。现在,当调用移动构造函数时,移动的列表与一个空列表交换(list 文件中的注释也通过说swap with empty *this 确认了这一点)。因此没有noexcept。 GCC 显然使用了不同但同样有效的 std::list 实现。
  • 不同 std::libs 的容器特殊成员的 noexcept 总结:howardhinnant.github.io/container_summary.html
  • 解决方法:v.insert(v.end(), std::move(l));
  • LWG 问题 2158 跟踪的真正问题是仅移动类型的容器假装它们可以复制到类型特征。修复它,问题就会消失。
猜你喜欢
  • 2020-05-02
  • 1970-01-01
  • 2022-01-07
  • 2020-08-17
  • 2015-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多