虽然没有使用,但需要C ++拷贝构造函数

时间:2015-05-22 15:11:27

标签: c++ c++11 move-semantics

在这种情况下,任何人都知道为什么编译器需要Foo的复制构造函数:

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

编译器(g ++)抱怨复制构造函数被删除。 但在那种情况下它不应该需要吗?

那我在这里错过了什么?

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

2 个答案:

答案 0 :(得分:8)

原因是push_back超载Foo&&而非const Foo&&

const Foo&&是多余的。它是一种合法的类型,但它的存在是不合时宜的。

这个编译:

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

答案 1 :(得分:2)

push_back方法有两个重载:

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

如果您使用第一个,T(在您的情况下为Foo)必须为&#34; CopyInsertable&#34;。如果你使用第二个,它必须是&#34; MoveInsertable&#34;。

您的passFoo2函数会收到const Foo&&引用,并且由于它是const - 合格(请参阅下面的注释),因此第一次重载是最佳匹配。因此,调用该重载,这需要您的类Foo可以复制。

注意:函数std::move转换命名对象以使其匿名,因此,适合通过rvalue-reference绑定,但它不会更改{ {1}}资格(移动后是const匿名对象)。因此,调用第一个重载。