简体   繁体   中英

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

I am passing a vector of std::unique_ptr of objects A as a parameter to a constructor of objects Obj . This is working when I use the std::move syntax as is shown below. However, if I add another object to the constructor's parameter list (the mpq_class i in the below code) I get an error message that reads

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

on OS X and

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>]’

on a linux system.

In the function getVector() the vector of unique_ptr is created, then passed to the Obj constructor and the objects are added to another vector and returned.

My question is why the code tries to call a copy constructor if I use std::move for the unique_ptrs and how to get rid of it!

The code that produces the error is shown below.

// 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;
}

The whole error message reads:

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.

Culprit is mpq_class . With simple dummy version it compiles fine (I commented out headers for gmp) :

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

However, when you make that class not movable:

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;}
};

Your problem comes back.

So issue that if mpq_class is not movable then Obj is not movable either and usage of emplace_back implicitly generates code to copy Obj in case of relocation which fails to compile because std::unique_ptr<A> is not copyable.

[wrong, see below]

The problem is with the definition of the Obj constructor. Its second argument is passed by value, which results in a copy being made. The fact that you use std::move in the initializer list does not change this fact.

The remedy is to use an rvalue reference for the second argument of the Obj constructor.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM