How can I get this code involving unique_ptr to compile? - c++

#include <vector>
#include <memory>
using namespace std;
class A {
public:
A(): i(new int) {}
A(A const& a) = delete;
A(A &&a): i(move(a.i)) {}
unique_ptr<int> i;
};
class AGroup {
public:
void AddA(A &&a) { a_.emplace_back(move(a)); }
vector<A> a_;
};
int main() {
AGroup ag;
ag.AddA(A());
return 0;
}
does not compile... (says that unique_ptr's copy constructor is deleted)
I tried replacing move with forward. Not sure if I did it right, but it didn't work for me.
[~/nn/src] g++ a.cc -o a -std=c++0x
/opt/local/include/gcc44/c++/bits/unique_ptr.h: In member function 'A& A::operator=(const A&)':
a.cc:6: instantiated from 'void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, _Args&& ...) [with _Args = A, _Tp = A, _Alloc = std::allocator<A>]'
/opt/local/include/gcc44/c++/bits/vector.tcc:100: instantiated from 'void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = A, _Tp = A, _Alloc = std::allocator<A>]'
a.cc:17: instantiated from here
/opt/local/include/gcc44/c++/bits/unique_ptr.h:219: error: deleted function 'std::unique_ptr<_Tp, _Tp_Deleter>& std::unique_ptr<_Tp, _Tp_Deleter>::operator=(const std::unique_ptr<_Tp, _Tp_Deleter>&) [with _Tp = int, _Tp_Deleter = std::default_delete<int>]'
a.cc:6: error: used here
In file included from /opt/local/include/gcc44/c++/vector:69,
from a.cc:1:
/opt/local/include/gcc44/c++/bits/vector.tcc: In member function 'void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, _Args&& ...) [with _Args = A, _Tp = A, _Alloc = std::allocator<A>]':
/opt/local/include/gcc44/c++/bits/vector.tcc:100: instantiated from 'void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = A, _Tp = A, _Alloc = std::allocator<A>]'
a.cc:17: instantiated from here
/opt/local/include/gcc44/c++/bits/vector.tcc:314: note: synthesized method 'A& A::operator=(const A&)' first required here

Probably your standard library doesn't (yet) define unique_ptr<T>::unique_ptr(unique_ptr &&). I checked my headers in 4.5 and it's there, so maybe try upgrading.
When it fails to find the move constructor, it would look for the copy constructor and find it deleted.
I get other errors when I compile that, though.
EDIT: Got it to work. I don't understand why you have to move an object which is already an rvalue reference, but you do. The only problem was a missing assigment operator.
#include <vector>
#include <memory>
using namespace std;
class A {
public:
A(): i(new int) {}
A(A const& a) = delete;
A &operator=(A const &) = delete;
A(A &&a): i(move(a.i)) {}
A &operator=(A &&a ) { i = move(a.i); }
unique_ptr<int> i;
};
class AGroup {
public:
void AddA(A &&a) { a_.emplace_back(move(a)); }
vector<A> a_;
};
int main() {
AGroup ag;
ag.AddA(A());
return 0;
}

Related

How to fix vector of objects that have unique_ptr

I have following code that has vector of a class that has some member declared as unique_ptr.
struct Container
{
struct Nested{
std::unique_ptr<Container> node;
Nested(std::unique_ptr<Container> t) : node(std::move(t)) {}
Nested(const Nested& t) { node = std::move(t.node); };
};
std::vector<Nested> edges;
};
typedef std::unique_ptr<Container> UCont;
typedef Container::Nested Nested;
int main()
{
std::unique_ptr<Container> object = UCont(new Container{{
Nested(UCont(new Container{{}})),
Nested(UCont(new Container{{}})),
Nested(UCont(new Container{{}}))
}});
}
Now compiling this is giving the following error:
..\00.UniquePtrVector.cpp: In copy constructor 'Container::Nested::Nested(const Container::Nested&)':
..\00.UniquePtrVector.cpp:20:35: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>& std::unique_ptr<_Tp, _Dp>::operator=(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Container; _Dp = std::default_delete<Container>]'
Nested(const Nested& t) { node = std::move(t.node); };
^
In file included from c:\mingw\lib\gcc\mingw32\5.3.0\include\c++\bits\locale_conv.h:41:0,
from c:\mingw\lib\gcc\mingw32\5.3.0\include\c++\locale:43,
from c:\mingw\lib\gcc\mingw32\5.3.0\include\c++\iomanip:43,
from c:\mingw\lib\gcc\mingw32\5.3.0\include\c++\mingw32\bits\stdc++.h:71,
from ..\00.UniquePtrVector.cpp:10:
c:\mingw\lib\gcc\mingw32\5.3.0\include\c++\bits\unique_ptr.h:357:19: note: declared here
unique_ptr& operator=(const unique_ptr&) = delete;
I am not sure how to fix this error. I guess removing the copy constructor is not an option either. Any help?
EDIT:
Changing to
Nested(std::unique_ptr<Container>&& t) : node(std::move(t)) {}
Nested(Nested&& t) : node(std::move(t.node)) {}
Nested(const Nested& t) =delete;
is also giving error:
In file included from c:\mingw\lib\gcc\mingw32\5.3.0\include\c++\bits\stl_tempbuf.h:60:0,
from c:\mingw\lib\gcc\mingw32\5.3.0\include\c++\bits\stl_algo.h:62,
from c:\mingw\lib\gcc\mingw32\5.3.0\include\c++\algorithm:62,
from c:\mingw\lib\gcc\mingw32\5.3.0\include\c++\mingw32\bits\stdc++.h:64,
from ..\00.UniquePtrVector.cpp:10:
c:\mingw\lib\gcc\mingw32\5.3.0\include\c++\bits\stl_construct.h: In instantiation of 'void std::_Construct(_T1*, _Args&& ...) [with _T1 = Container::Nested; _Args = {const Container::Nested&}]':
c:\mingw\lib\gcc\mingw32\5.3.0\include\c++\bits\stl_uninitialized.h:75:18: required from 'static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = const Container::Nested*; _ForwardIterator = Container::Nested*; bool _TrivialValueTypes = false]'
c:\mingw\lib\gcc\mingw32\5.3.0\include\c++\bits\stl_uninitialized.h:126:15: required from '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = const Container::Nested*; _ForwardIterator = Container::Nested*]'
c:\mingw\lib\gcc\mingw32\5.3.0\include\c++\bits\stl_uninitialized.h:281:37: required from '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = const Container::Nested*; _ForwardIterator = Container::Nested*; _Tp = Container::Nested]'
c:\mingw\lib\gcc\mingw32\5.3.0\include\c++\bits\stl_vector.h:1290:33: required from 'void std::vector<_Tp, _Alloc>::_M_range_initialize(_ForwardIterator, _ForwardIterator, std::forward_iterator_tag) [with _ForwardIterator = const Container::Nested*; _Tp = Container::Nested; _Alloc = std::allocator<Container::Nested>]'
c:\mingw\lib\gcc\mingw32\5.3.0\include\c++\bits\stl_vector.h:377:21: required from 'std::vector<_Tp, _Alloc>::vector(std::initializer_list<_Tp>, const allocator_type&) [with _Tp = Container::Nested; _Alloc = std::allocator<Container::Nested>; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<Container::Nested>]'
..\00.UniquePtrVector.cpp:36:11: required from here
c:\mingw\lib\gcc\mingw32\5.3.0\include\c++\bits\stl_construct.h:75:7: error: use of deleted function 'Container::Nested::Nested(const Container::Nested&)'
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
^
..\00.UniquePtrVector.cpp:20:11: note: declared here
Nested(const Nested& t) =delete;
^
When you move t.node in your copy constructor, t.node needs to change. But t is const, so the move is invalid. unique_ptr cannot be copy constructed, thus struct Nested cannot be copy constructed either.
To make it work, you'll need to supply a move constructor and delete the copy constructor. Something like this:
struct Nested{
std::unique_ptr<Container> node;
Nested(std::unique_ptr<Container>&& t) : node(std::move(t)) {}
Nested(Nested&& t) : node(std::move(t.node)) {}
Nested(const Nested& t) =delete;
};
tl;dr : Consider using the rule of zero
I would be wary of explicitly specifying all those constructors in your class. The fact that unique_ptr's can't be copied will get you in all sorts of trouble when you do things the way you tried to. Here's what happens when, instead, you don't specify any constructors:
#include <vector>
#include <memory>
struct Container
{
struct Nested{
std::unique_ptr<Container> node;
//
// Nested(std::unique_ptr<Container> t) : node(std::move(t)) {}
// Nested(const Nested& t) { node = std::move(t.node); };
};
std::vector<Nested> edges;
};
typedef std::unique_ptr<Container> UCont;
typedef Container::Nested Nested;
int main()
{
auto c1 = new Container{};
auto c2 = new Container{};
auto c3 = new Container{};
std::unique_ptr<Container> u1 {c1};
std::unique_ptr<Container> u2 {c2};
std::unique_ptr<Container> u3 {c3};
Nested n1 {std::move(u1)};
Nested n2 {std::move(u2)};
Nested n3 {std::move(u3)};
auto v = std::vector<Nested>{3};
v.push_back(std::move(n1));
v.push_back(std::move(n2));
v.push_back(std::move(n3));
auto c5 = new Container { std::move(v) };
std::unique_ptr<Container> object = UCont(std::move(c5));
}
I've broken everything down to shorter statements for clarity (mostly).
The root cause of the error I was getting is due to use of unique_ptr inside the object that is used in intializer list. Similar to vector of simple unique_ptr (as in here Initializing container of unique_ptrs from initializer list fails with GCC 4.7 ) an object that also has unique_ptr in its data model can also NOT be used in initializer list.
Similar to the other link, cause is same; initializer list always performs copies and unique_ptr cannot be copied. So we have to use emplace_back/push_back.
So even with constructor in place the following solution works
struct Container
{
struct Nested{
std::unique_ptr<Container> node;
Nested(): node(nullptr) {}
Nested(std::unique_ptr<Container> t) : node(std::move(t)) {}
};
std::vector<Nested> edges;
};
typedef std::unique_ptr<Container> UCont;
typedef Container::Nested Nested;
int main()
{
auto v = std::vector<Nested>{3};
v.push_back(std::move(Nested(std::move(std::unique_ptr<Container>(new Container{})))));
v.push_back(std::move(Nested(std::move(std::unique_ptr<Container>(new Container{})))));
v.push_back(std::move(Nested(std::move(std::unique_ptr<Container>(new Container{})))));
std::unique_ptr<Container> object = UCont(new Container { std::move(v) });
}

std::vector doesn't call move constructor with objects with noexcept move constructs

I've been struggeling a lot lately with move and copy constructors and can't seem to find the awnser on my own.
The structure is fairly simple. A class OWUP which holds a std::unique_ptr to an object (in this example an int), a class One which is a simple wrapper around std::vector of OWUP's and class Two which is a simple wrapper std::vector of One's.
#include <memory>
#include <vector>
class OWUP {
public:
OWUP()
: data(nullptr)
{ }
OWUP(const OWUP &) = delete;
OWUP &operator=(const OWUP &) = delete;
OWUP(OWUP &&) noexcept = default;
OWUP &operator=(OWUP &&) noexcept = default;
std::unique_ptr<int> data;
};
class One {
public:
One(std::size_t numof_datas)
: datas(numof_datas)
{ }
One(const One &) = delete;
One &operator=(const One &) = delete;
One(One &&) noexcept = default;
One &operator=(One &&) noexcept = default;
std::vector<OWUP> datas;
};
class Two {
public:
Two(std::size_t numof_ones, std::size_t num_of_datas)
: ones(numof_ones, One(num_of_datas))
{ }
Two(const Two &) = delete;
Two &operator=(const Two &) = delete;
Two(Two &&) noexcept = default;
Two &operator=(Two &&) noexcept = default;
std::vector<One> ones;
};
The code gets the following error code with g++ -std=c++14 example.cpp
In file included from /usr/include/c++/7.3.1/memory:64:0,
from example.cpp:1:
/usr/include/c++/7.3.1/bits/stl_construct.h: In instantiation of 'void std::_Construct(_T1*, _Args&& ...) [with _T1 = One; _Args = {const One&}]':
/usr/include/c++/7.3.1/bits/stl_uninitialized.h:210:18: required from 'static _ForwardIterator std::__uninitialized_fill_n<_TrivialValueType>::__uninit_fill_n(_ForwardIterator, _Size, const _Tp&) [with _ForwardIterator = One*; _Size = long unsigned int; _Tp = One; bool _TrivialValueType = false]'
/usr/include/c++/7.3.1/bits/stl_uninitialized.h:255:17: required from '_ForwardIterator std::uninitialized_fill_n(_ForwardIterator, _Size, const _Tp&) [with _ForwardIterator = One*; _Size = long unsigned int; _Tp = One]'
/usr/include/c++/7.3.1/bits/stl_uninitialized.h:366:39: required from '_ForwardIterator std::__uninitialized_fill_n_a(_ForwardIterator, _Size, const _Tp&, std::allocator<_Tp2>&) [with _ForwardIterator = One*; _Size = long unsigned int; _Tp = One; _Tp2 = One]'
/usr/include/c++/7.3.1/bits/stl_vector.h:1337:33: required from 'void std::vector<_Tp, _Alloc>::_M_fill_initialize(std::vector<_Tp, _Alloc>::size_type, const value_type&) [with _Tp = One; _Alloc = std::allocator<One>; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::value_type = One]'
/usr/include/c++/7.3.1/bits/stl_vector.h:298:27: required from 'std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>::size_type, const value_type&, const allocator_type&) [with _Tp = One; _Alloc = std::allocator<One>; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::value_type = One; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<One>]'
example.cpp:40:39: required from here
/usr/include/c++/7.3.1/bits/stl_construct.h:75:7: error: use of deleted function 'One::One(const One&)'
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
example.cpp:29:3: note: declared here
One(const One &) = delete;
^~~
I've tried my best to force it to use move constructors. I also tried to create my own move constructors with std::move, but that resulted int the same compile error. I'm aware that std::vector tests for move_if_noexcept(), but for can't find out why it doesn't. What is it that i'm doing wrong?
Because the problem is here:
Two(std::size_t numof_ones, std::size_t num_of_datas)
: ones(numof_ones, One(num_of_datas))
{ }
You can't move from One you create here, you really need to copy from it numof_ones times.
Unfortunately, there is no easy way of constructing a std::vector<One> of size numof_ones without One having a default constructor or a copy constructor. The constructor you chose takes numof_ones copies of the single value you give it into each element of the vector.
The easiest solution is probably to not initialize ones in the constructor initializer list but instead initialize it in the body of the constructor:
Two(std::size_t numof_ones, std::size_t num_of_datas) {
ones.reserve(numof_ones);
for (size_t i = 0; i != numof_ones; ++i) {
ones.emplace_back(num_of_datas);
}
}
(Technically you could probably use the std::vector constructor that takes two iterators and provide your own custom iterator but it is probably not worth the effort).

C++ copy constructor needed although not used

Anybody knows why the compiler needs a copy constructor for Foo in this situation:
#include <iostream>
#include <list>
class Foo {
public:
Foo() {}
Foo(const Foo &&f) noexcept {}
Foo(const Foo &f) = delete;
~Foo() {}
};
void passFoo2(const Foo&& f) {
std::list<Foo> l;
l.push_back(std::move(f));
}
int main(int argc, char **argv) {
Foo f;
passFoo2(std::move(f));
return 0;
}
The compiler (g++) complains the copy constructor is deleted.
But it should not need it in that case?
So what am I missing here?
x#ubuntu:/tmp/c++$ g++ stackoverflow.cxx -std=c++11
In file included from /usr/include/c++/4.9/list:63:0,
from stackoverflow.cxx:2:
/usr/include/c++/4.9/bits/stl_list.h: In instantiation of std::_List_node<_Tp>::_List_node(_Args&& ...) [with _Args = {const Foo&}; _Tp = Foo]:
/usr/include/c++/4.9/ext/new_allocator.h:120:4: required from void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::_List_node<Foo>; _Args = {const Foo&}; _Tp = std::_List_node<Foo>]
/usr/include/c++/4.9/bits/stl_list.h:514:8: required from std::list<_Tp, _Alloc>::_Node* std::list<_Tp, _Alloc>::_M_create_node(_Args&& ...) [with _Args = {const Foo&}; _Tp = Foo; _Alloc = std::allocator<Foo>; std::list<_Tp, _Alloc>::_Node = std::_List_node<Foo>]
/usr/include/c++/4.9/bits/stl_list.h:1688:63: required from void std::list<_Tp, _Alloc>::_M_insert(std::list<_Tp, _Alloc>::iterator, _Args&& ...) [with _Args = {const Foo&}; _Tp = Foo; _Alloc = std::allocator<Foo>; std::list<_Tp, _Alloc>::iterator = std::_List_iterator<Foo>]
/usr/include/c++/4.9/bits/stl_list.h:1029:9: required from void std::list<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = Foo; _Alloc = std::allocator<Foo>; std::list<_Tp, _Alloc>::value_type = Foo]
stackoverflow.cxx:14:30: required from here
/usr/include/c++/4.9/bits/stl_list.h:114:71: error: use of deleted function Foo::Foo(const Foo&)
: __detail::_List_node_base(), _M_data(std::forward<_Args>(__args)...)
^
stackoverflow.cxx:8:3: note: declared here
Foo(const Foo &f) = delete;
^
the reason is that push_back has an overload for Foo&& not const Foo&&.
const Foo&& is superfluous. It's a legal type but its existence is an anachronism.
this compiles:
#include <iostream>
#include <list>
class Foo {
public:
Foo() {}
Foo( Foo &&f) noexcept {}
Foo(const Foo &f) = delete;
~Foo() {}
};
void passFoo2(Foo&& f) {
std::list<Foo> list;
list.push_back(std::move(f));
}
int main(int argc, char **argv) {
Foo f;
passFoo2(std::move(f));
return 0;
}
The push_back method has two overloads:
void push_back( const T& value );
void push_back( T&& value );
If you use the first one, T (Foo in your case) must be "CopyInsertable". If you use the second one, it must be "MoveInsertable".
Your passFoo2 function receives a const Foo&& reference, and since it is const-qualified (see note below), the first overload is the best match. So, that overload is called, which requires your class Foo to be copyable.
Note: Function std::move transform a named-object to make it anonymous, and so, suitable to be binded by a rvalue-reference, but it doesn't change const qualifications (it is a const Foo anonymous object after the movement). For this reason the first overload is called.

C++ Vector of classes push back error

I'm new in C++ , i use G++ compiler (Ubuntu 4.8.1-2ubuntu1~12.04) 4.8.1
i try to implement undirected wieghted Graph. by two classes Edges and Graph. but the compiler gives me this error
the compiler gives this error
/usr/include/c++/4.8/ext/new_allocator.h: In instantiation of 'void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...)
[with _Up = UNDIR_W_EDGE; _Args = {const UNDIR_W_EDGE&}; _Tp =
UNDIR_W_EDGE]':
/usr/include/c++/4.8/bits/alloc_traits.h:254:4: required from 'static typename
std::enable_ifAlloc>::_construct_helper<_Tp,
_Args>::value, void>::type std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&&
...) [with _Tp = UNDIR_W_EDGE; _Args = {const UNDIR_W_EDGE&}; _Alloc =
std::allocator; typename
std::enable_ifAlloc>::_construct_helper<_Tp,
_Args>::value, void>::type = void]'
/usr/include/c++/4.8/bits/alloc_traits.h:393:57: required from 'static decltype (_S_construct(__a, __p,
(forward<_Args>)(std::allocator_traits::construct::__args)...))
std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...)
[with _Tp = UNDIR_W_EDGE; _Args = {const UNDIR_W_EDGE&}; _Alloc =
std::allocator; decltype (_S_construct(__a, __p,
(forward<_Args>)(std::allocator_traits::construct::__args)...)) =
]'
/usr/include/c++/4.8/bits/stl_vector.h:906:34: required from 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp
= UNDIR_W_EDGE; _Alloc = std::allocator; std::vector<_Tp, _Alloc>::value_type = UNDIR_W_EDGE]'
../src/GRAPH.h:31:5: required from 'void GRAPH::addEdge(const Edge&) [with Edge = UNDIR_W_EDGE]'
../src/main.cpp:32:13: required from here
/usr/include/c++/4.8/ext/new_allocator.h:120:4: error: no matching function for call to 'UNDIR_W_EDGE::UNDIR_W_EDGE(const UNDIR_W_EDGE&)'
{ ::new((void *)__p) _Up(std::forward<Args>(_args)...); }
The Code
GRAPH.h file
#include "vector"
template <typename Edge>
class GRAPH {
private:
// Implementation-dependent code
int Vcnt;
int Ecnt;
std::vector<std::vector< Edge > > adj;
public:
GRAPH(int x):Vcnt(x),Ecnt(0) {
adj.resize(Vcnt);
}
virtual ~GRAPH();
virtual int V() const;
virtual int E() const;
virtual void addEdge(const Edge &e){
adj[e.V()].push_back(e);
adj[e.W()].push_back(e);
Ecnt++;
};
virtual std::vector< Edge > adjIterator(int) const;
};
UNDIRWEDGE.h file
class UNDIR_W_EDGE {
int v,w;
float weight;
public:
UNDIR_W_EDGE(int v, int w, float weight);
UNDIR_W_EDGE(UNDIR_W_EDGE &);
virtual ~UNDIR_W_EDGE();
virtual int V()const;
virtual int W()const;
virtual float WEIGHT()const;
virtual int CompareTo(UNDIR_W_EDGE e)const;
};
in UNDIRWEDGE.cpp
inline int UNDIR_W_EDGE::CompareTo(UNDIR_W_EDGE e)const{
if(this->weight > e.weight) return 1;
else if (this->weight < e.weight)return -1;
else return 0;
}
in main.cpp
GRAPH<UNDIR_W_EDGE> g(10);
UNDIR_W_EDGE e(0,7,0.0);
g.addEdge(e);
You don't have a copy constructor for UNDIR_W_EDGE.
The copy constructor is required inside std::vector<UNDIR_W_EDGE>, as well as in CompareTo which takes its argument by value (for some reason).
You do have this:
UNDIR_W_EDGE(UNDIR_W_EDGE &);
Presumably you intended for it to be:
UNDIR_W_EDGE(const UNDIR_W_EDGE&);

Why const member caused error?

#include <vector>
class B {
};
class A {
const std::vector<B> m_v;
public:
A(const std::vector<B>& v) : m_v(v) {}
void doSomething() {}
};
void foo(void* bar) {
A* a = (A*)bar;
a->doSomething();
}
int main() {
std::vector<B> v;
std::vector<A > l;
for (auto i = 0; i < 10; i++) {
A a(v);
l.push_back(std::move(a));
foo((void*)&l[i]);
}
return 0;
}
$ g++ -Wall initList.cpp -o initList -lrt -O3 -std=c++0x
In file included from /usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../../../include/c++/4.6.2/vector:70:0,
from initList.cpp:1:
/usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../../../include/c++/4.6.2/bits/vector.tcc: In member function \u2018void std::vector::_M_insert_aux(std::vector::iterator, _Args&& ...) [with _Args = {A}, _Tp = A, _Alloc = std::allocator, std::vector::iterator = __gnu_cxx::__normal_iterator >, typename std::_Vector_base::_Tp_alloc_type::pointer = A*]`:
/usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../../../include/c++/4.6.2/bits/vector.tcc:102:4: instantiated from \u2018void std::vector::emplace_back(_Args&& ...) [with _Args = {A}, _Tp = A, _Alloc = std::allocator]`
/usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../../../include/c++/4.6.2/bits/stl_vector.h:840:9: instantiated from \u2018void std::vector::push_back(std::vector::value_type&&) [with _Tp = A, _Alloc = std::allocator, std::vector::value_type = A]`
initList.cpp:23:27: instantiated from here
/usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../../../include/c++/4.6.2/bits/vector.tcc:319:4: error: use of deleted function '& A::operator=(const A&)`
initList.cpp:6:7: error: '& A::operator=(const A&)` is implicitly deleted because the default definition would be ill-formed:
initList.cpp:6:7: error: passing \u2018const std::vector` as \u2018this` argument of \u2018std::vector& std::vector::operator=(const std::vector&) [with _Tp = B, _Alloc = std::allocator]` discards qualifiers [-fpermissive]
In file included from /usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../../../include/c++/4.6.2/vector:61:0,
from initList.cpp:1:
/usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../../../include/c++/4.6.2/bits/stl_algobase.h: In static member function \u2018static _BI2 std::__copy_move_backward::__copy_move_b(_BI1, _BI1, _BI2) [with _BI1 = A*, _BI2 = A*]`:
/usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../../../include/c++/4.6.2/bits/stl_algobase.h:581:18: instantiated from \u2018_BI2 std::__copy_move_backward_a(_BI1, _BI1, _BI2) [with bool _IsMove = true, _BI1 = A*, _BI2 = A*]`
/usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../../../include/c++/4.6.2/bits/stl_algobase.h:590:34: instantiated from \u2018_BI2 std::__copy_move_backward_a2(_BI1, _BI1, _BI2) [with bool _IsMove = true, _BI1 = A*, _BI2 = A*]`
/usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../../../include/c++/4.6.2/bits/stl_algobase.h:661:15: instantiated from \u2018_BI2 std::move_backward(_BI1, _BI1, _BI2) [with _BI1 = A*, _BI2 = A*]`
/usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../../../include/c++/4.6.2/bits/vector.tcc:313:4: instantiated from \u2018void std::vector::_M_insert_aux(std::vector::iterator, _Args&& ...) [with _Args = {A}, _Tp = A, _Alloc = std::allocator, std::vector::iterator = __gnu_cxx::__normal_iterator >, typename std::_Vector_base::_Tp_alloc_type::pointer = A*]`
/usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../../../include/c++/4.6.2/bits/vector.tcc:102:4: instantiated from \u2018void std::vector::emplace_back(_Args&& ...) [with _Args = {A}, _Tp = A, _Alloc = std::allocator]`
/usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../../../include/c++/4.6.2/bits/stl_vector.h:840:9: instantiated from \u2018void std::vector::push_back(std::vector::value_type&&) [with _Tp = A, _Alloc = std::allocator, std::vector::value_type = A]`
initList.cpp:23:27: instantiated from here
/usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../../../include/c++/4.6.2/bits/stl_algobase.h:546:6: error: use of deleted function '& A::operator=(const A&)`
If I don't specify const for m_v. It compiles fine.
The error suggests something with assign operator, which I don't see how it is invoked.
Any idea?
Thanks in advance.
It's a bug in older versions of GCC/libstdc++, your code compiles fine with GCC 4.8.1. Live example. The bug is triggered by
l.push_back(std::move(a));
as older versions of GCC tried to create a default-constructed element in the vector and assigned the parameter std::move(a) to it in a second step instead of using the in-place copy/move-ctor.