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.