C ++ copy constructor required, although not used

Does anyone know 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 that the copy constructor has been removed. But in this case it is not necessary?

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

      

+3


source to share


2 answers


The method push_back

has two overloads:

void push_back( const T& value );
void push_back( T&& value );

      

If you are using the former, T

( Foo

in your case) there should be "CopyInsertable". If you are using the second one, it must be "MoveInsertable".



Your function passFoo2

is referenced const Foo&&

, and since it is const

-qualified (see note below), the first overload is the best match. Thus, an overload is called which requires your class Foo

to be copyable.

Note: The function std::move

transforms a named object to make it anonymous, and therefore is suitable for binding with an rvalue reference, but does not change the qualification of const

that anonymous object const Foo

after movement). For this reason, the first overload is called.

+2


source


the reason is that push_back has an overload for Foo&&

not const Foo&&

.

const Foo&&

is overkill. It is a legal type, but its existence is anachronistic.



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

      

+8


source







All Articles