seyfe
seyfe

Reputation: 476

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.

Upvotes: 2

Views: 5104

Answers (2)

sh-
sh-

Reputation: 1031

[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.

Upvotes: -3

Slava
Slava

Reputation: 44288

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.

Upvotes: 9

Related Questions