【问题标题】:strange error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr when no pointers really created奇怪的错误:在没有真正创建指针时使用已删除的函数 'std::unique_ptr<_Tp, _Dp>::unique_ptr
【发布时间】:2017-04-24 22:01:00
【问题描述】:

我有一个类,看起来像这样:

    template<typename T>
    using VectorPtr=std::vector<std::unique_ptr<T>>;

    template<typename T>
    using VectorRawPtr=std::vector<T*>;

    class ItemsSet{ // <-- Compiler say this line contans an error 0_o ?
    public:
          ItemsSet(VectorPtr<Item>& items);  

          ~ItemsSet() = default;

           VectorRawPtr<Item> GetItems();

           VectorRawPtr<Item> GetSuitableItemsForPeriod(const IPeriod &period);

           double CalculateTotal();
    private:
       VectorPtr<Item> _items;
    };

构造函数看起来像:

ItemsSet::ItemsSet(VectorPtr<Item> & items) {
     for(auto &itm: items){
        _items.emplace_back(std::move(itm));
     }
}

但是此代码未编译并因错误而失败:

/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/stl_construct.h: In instantiation of 'void std::_Construct(_T1*, _Args&& ...) [with _T1 = std::unique_ptr<Item, std::default_delete<Item> >; _Args = {const std::unique_ptr<Item, std::default_delete<Item> >&}]':
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/stl_uninitialized.h:75:18:   required from 'static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<Item, std::default_delete<Item> >*, std::vector<std::unique_ptr<Item, std::default_delete<Item> >, std::allocator<std::unique_ptr<Item, std::default_delete<Item> > > > >; _ForwardIterator = std::unique_ptr<Item, std::default_delete<Item> >*; bool _TrivialValueTypes = false]'
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/stl_uninitialized.h:126:15:   required from '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<Item, std::default_delete<Item> >*, std::vector<std::unique_ptr<Item, std::default_delete<Item> >, std::allocator<std::unique_ptr<Item, std::default_delete<Item> > > > >; _ForwardIterator = std::unique_ptr<Item, std::default_delete<Item> >*]'
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/stl_uninitialized.h:281:37:   required from '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<Item, std::default_delete<Item> >*, std::vector<std::unique_ptr<Item, std::default_delete<Item> >, std::allocator<std::unique_ptr<Item, std::default_delete<Item> > > > >; _ForwardIterator = std::unique_ptr<Item, std::default_delete<Item> >*; _Tp = std::unique_ptr<Item, std::default_delete<Item> >]'
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/stl_vector.h:322:31:   required from 'std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = std::unique_ptr<Item, std::default_delete<Item> >; _Alloc = std::allocator<std::unique_ptr<Item, std::default_delete<Item> > >]'
/cygdrive/d/code/itemSet.h:4:19:   required from here
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/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 = Item; _Dp = std::default_delete<Item>]'
     { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }

谁能解释我做错了什么以及如何解决我的问题?

【问题讨论】:

  • 也许错误是由于GetItems()?它没有返回引用,因此会复制向量(这反过来会尝试复制其中的所有unique_ptrs)。 GetSuitableItemsForPeriod() 也可能有同样的问题。根据您发布的代码,似乎此类使用 shared_ptr 而不是 unique_ptr 会更好。
  • @Andy 我更新了问题并更改了这些方法以返回原始指针,但错误仍然存​​在。
  • 返回原始指针似乎非常危险——这正是shared_ptr 设计的那种情况。我能想到的唯一另一件事是它与_items 的初始化有关。您可以尝试按照答案中的建议将构造函数参数直接移动到_items
  • @Andy 将构造函数更改为 ItemsSet(VectorPtr&& items) 并且在里面移动项目没有任何效果
  • 我不是这个意思 - 我会添加一个答案,在那里更容易解释。

标签: c++ c++11 compiler-errors c++14 unique-ptr


【解决方案1】:

我很确定实际问题是 ItemsSetItem 的隐式复制构造函数。因为您使用的unique_ptr 不能真正被复制,所以无法正确生成复制构造函数。尝试显式删除复制构造函数并找到它们使用的位置并更改这些位置以移动声明,例如,或使用共享指针。

【讨论】:

  • 谢谢,是的,我尝试在几个地方复制 ItemSet。当我将它们更改为 ItemSet& 时,错误消失了。
  • 在您真正尝试复制 ItemsSet 之前,这很重要。此处未显示。
【解决方案2】:

这不是产生错误的实际代码(您的行号不匹配,错误也不匹配;您应该在这里提供一个实际的测试用例),但我们仍然可以看到问题。

unique_ptrs 不能被复制(它们是“唯一的”!),但是通过从它们的整个向量中复制初始化 _items,你正试图复制它们。你不能那样做。

您可以将构造函数参数移动_items

【讨论】:

  • ItemsSet(VectorPtr&lt;Item&gt; items) 更改为ItemsSet(VectorPtr&lt;Item&gt;&amp; items) 并不能解决问题。
  • @silent_coder:问题出在您对该构造函数的定义中(特别是成员初始化列表)。您的问题不完整。
  • 我在问题中添加了构造函数代码,但编译器说它在头文件中失败,而不是在实现一中。我了解 unique_ptr 不允许复制,我不会复制它们。
  • 使构造函数参数右值引用并移动它们仍然不能解决问题。
【解决方案3】:

我不知道这是否会解决它,但您可以尝试将构造函数参数直接移动到_items,而不是将每个单独的成员移动到其中:

 ItemsSet::ItemsSet(VectorPtr<Item>&& items)
 : _items(std::move(items))
 {
 }

【讨论】:

  • 不幸的是,我认为这没有理由更好地工作。
  • 是的,这并不能解决问题 =( 我实际上也尝试过同样的方法,只是将这段代码保存在 cpp 文件中。
  • 我刚刚遇到了类似的问题。 std::movestd::forward 一样工作,但我无法解释原因。
猜你喜欢
  • 2022-01-07
  • 1970-01-01
  • 2019-11-11
  • 1970-01-01
  • 1970-01-01
  • 2020-09-16
  • 1970-01-01
相关资源
最近更新 更多