矢量<unique_ptr构造<A>函数中的> - 错误:调用隐式删除的复制构造函数

vector<unique_ptr<A> > in constructor - error: call to implicitly-deleted copy constructor

本文关键字:gt lt 调用 删除 构造函数 复制 错误 函数 ptr unique 构造      更新时间:2023-10-16

我将对象Astd::unique_ptr向量作为参数传递给对象Obj的构造函数。当我使用std::move语法时,这是有效的,如下所示。然而,如果我在构造函数的参数列表中添加另一个对象(下面代码中的mpq_class i),我将得到一个错误消息,读取

error: call to implicitly-deleted copy constructor of 'std::__1::unique_ptr<A, std::__1::default_delete<A> >'

在OS X和

error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Interface; _Dp = std::default_delete<Interface>]’

在Linux系统上。

在函数getVector()中,创建了unique_ptr的向量,然后传递给Obj构造函数,并将对象添加到另一个向量中并返回。

我的问题是为什么代码试图调用复制构造函数,如果我使用std::move的unique_ptrs,以及如何摆脱它!

产生错误的代码如下所示。

// g++ -Wall -O3 -std=c++1y -lgmpxx -lgmp
#include <vector>
#include <gmpxx.h>
#include <gmp.h>
#include <memory>
#include <iostream>
class A {
public:
    A( int y ) : x(y) {}
    int x;  
};

class Obj {
public:
    Obj( mpq_class i, std::vector<std::unique_ptr<A> > v ) : number(i), cont( std::move(v) ) {}
    mpq_class number;
    std::vector<std::unique_ptr<A> > cont;
};

std::vector<Obj> getVector()
{
    std::vector<Obj> result;
    int M = 3, N = 5;
    for( int mm = 0; mm < M; mm++ )
    {
        mpq_class rational;
        std::vector<std::unique_ptr<A> > abstractObjectsForConstructor;
        for(int nn = 0; nn < N; nn++ )
        {
            mpq_class r(mm,nn);
            rational = r;
            abstractObjectsForConstructor.push_back( std::make_unique<A>(nn) );
        }
        result.emplace_back( rational, std::move(abstractObjectsForConstructor) );
    }
    return result;
}
int main()
{
    std::vector<Obj> vec = getVector();
    for( unsigned int ii = 0; ii < vec.size(); ii++ )
    {
        for( unsigned int jj = 0; jj < vec[ii].cont.size(); jj++ )
        {
            std::cout << vec[ii].cont[jj]->x << 't' << std::endl;
        }
    }

    return 0;
}

整个错误信息如下:

In file included from vector_unique.cpp:2:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:265:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__bit_reference:15:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/algorithm:628:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:1645:31: error: 
      call to implicitly-deleted copy constructor of 'std::__1::unique_ptr<A, std::__1::default_delete<A> >'
            ::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
                              ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:1572:18: note: 
      in instantiation of function template specialization 'std::__1::allocator<std::__1::unique_ptr<A,
      std::__1::default_delete<A> > >::construct<std::__1::unique_ptr<A, std::__1::default_delete<A> >,
      std::__1::unique_ptr<A, std::__1::default_delete<A> > &>' requested here
            {__a.construct(__p, _VSTD::forward<_Args>(__args)...);}
                 ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:1453:14: note: 
      in instantiation of function template specialization
      'std::__1::allocator_traits<std::__1::allocator<std::__1::unique_ptr<A, std::__1::default_delete<A> > >
      >::__construct<std::__1::unique_ptr<A, std::__1::default_delete<A> >, std::__1::unique_ptr<A,
      std::__1::default_delete<A> > &>' requested here
            {__construct(__has_construct<allocator_type, pointer, _Args...>(),
             ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:1005:25: note: 
      in instantiation of function template specialization
      'std::__1::allocator_traits<std::__1::allocator<std::__1::unique_ptr<A, std::__1::default_delete<A> > >
      >::construct<std::__1::unique_ptr<A, std::__1::default_delete<A> >, std::__1::unique_ptr<A,
      std::__1::default_delete<A> > &>' requested here
        __alloc_traits::construct(__a, _VSTD::__to_raw_pointer(this->__end_), *__first);
                        ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:1203:9: note: 
      in instantiation of function template specialization 'std::__1::vector<std::__1::unique_ptr<A,
      std::__1::default_delete<A> >, std::__1::allocator<std::__1::unique_ptr<A, std::__1::default_delete<A> > >
      >::__construct_at_end<std::__1::unique_ptr<A, std::__1::default_delete<A> > *>' requested here
        __construct_at_end(__x.__begin_, __x.__end_);
        ^
vector_unique.cpp:15:8: note: in instantiation of member function 'std::__1::vector<std::__1::unique_ptr<A,
      std::__1::default_delete<A> >, std::__1::allocator<std::__1::unique_ptr<A, std::__1::default_delete<A> > >
      >::vector' requested here
        class Obj {
              ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:1572:18: note: 
      (skipping 2 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
            {__a.construct(__p, _VSTD::forward<_Args>(__args)...);}
                 ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:1535:17: note: 
      in instantiation of function template specialization 'std::__1::allocator_traits<std::__1::allocator<Obj>
      >::construct<Obj, const Obj &>' requested here
                construct(__a, _VSTD::__to_raw_pointer(__end2-1), _VSTD::move_if_noexcept(*--__end1));
                ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:874:21: note: 
      in instantiation of function template specialization 'std::__1::allocator_traits<std::__1::allocator<Obj>
      >::__construct_backward<Obj *>' requested here
    __alloc_traits::__construct_backward(this->__alloc(), this->__begin_, this->__end_, __v.__begin_);
                    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:1621:5: note: 
      in instantiation of member function 'std::__1::vector<Obj, std::__1::allocator<Obj>
      >::__swap_out_circular_buffer' requested here
    __swap_out_circular_buffer(__v);
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:1639:9: note: 
      in instantiation of function template specialization 'std::__1::vector<Obj, std::__1::allocator<Obj>
      >::__emplace_back_slow_path<__gmp_expr<mpq_t, mpq_t> &, std::__1::vector<std::__1::unique_ptr<A,
      std::__1::default_delete<A> >, std::__1::allocator<std::__1::unique_ptr<A, std::__1::default_delete<A> > > > >'
      requested here
        __emplace_back_slow_path(_VSTD::forward<_Args>(__args)...);
        ^
vector_unique.cpp:40:11: note: in instantiation of function template specialization 'std::__1::vector<Obj,
      std::__1::allocator<Obj> >::emplace_back<__gmp_expr<mpq_t, mpq_t> &, std::__1::vector<std::__1::unique_ptr<A,
      std::__1::default_delete<A> >, std::__1::allocator<std::__1::unique_ptr<A, std::__1::default_delete<A> > > > >'
      requested here
                        result.emplace_back( rational, std::move(abstractObjectsForConstructor) );
                               ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:2515:31: note: 
      copy constructor is implicitly deleted because 'unique_ptr<A, std::__1::default_delete<A> >' has a
      user-declared move constructor
    _LIBCPP_INLINE_VISIBILITY unique_ptr(unique_ptr&& __u) _NOEXCEPT
                              ^
1 error generated.

罪魁祸首是mpq_class。使用简单的虚拟版本,它编译得很好(我注释掉了gmp的头):

struct mpq_class {
   mpq_class() {}
   mpq_class( int, int );
};

然而,当你使这个类不可移动时:

struct mpq_class {
   mpq_class() {}
   mpq_class( int, int );
   mpq_class( const mpq_class & ) {}
   mpq_class( mpq_class && ) = delete;
   mpq_class &operator=( const mpq_class & ) {return *this;}
};

你的问题又来了。

因此,如果mpq_class不可移动,那么Obj也不可移动,并且emplace_back的使用隐式生成代码来复制Obj,以防止由于std::unique_ptr<A>不可复制而无法编译。

[错误,见下文]

问题出在Obj构造函数的定义上。它的第二个参数是按值传递的,这将产生一个副本。在初始化列表中使用std::move并不会改变这个事实。

补救方法是对Obj构造函数的第二个参数使用右值引用。