尽管未使用,但需要 C++ 复制构造函数
C++ copy constructor needed although not used
有人知道为什么编译器在这种情况下需要 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++ Whosebug.cxx -std=c++11
In file included from /usr/include/c++/4.9/list:63:0,
from Whosebug.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]
Whosebug.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)...)
^
Whosebug.cxx:8:3: note: declared here
Foo(const Foo &f) = delete;
^
原因是 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;
}
push_back
方法有两个重载:
void push_back( const T& value );
void push_back( T&& value );
如果您使用第一个,T
(在您的情况下是 Foo
)必须是 "CopyInsertable"。如果用第二个,那肯定是"MoveInsertable".
你的 passFoo2
函数接收到一个 const Foo&&
引用,并且由于它是 const
限定的(见下面的注释),第一个重载是最好的匹配。因此,调用了该重载,这要求您的 class Foo
是可复制的。
注意: 函数 std::move
转换命名对象使其匿名,因此适合由右值引用绑定,但它不t 改变const
资格(它是一个const Foo
移动后的匿名对象)。为此,调用了第一个重载。
有人知道为什么编译器在这种情况下需要 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++ Whosebug.cxx -std=c++11
In file included from /usr/include/c++/4.9/list:63:0,
from Whosebug.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]
Whosebug.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)...)
^
Whosebug.cxx:8:3: note: declared here
Foo(const Foo &f) = delete;
^
原因是 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;
}
push_back
方法有两个重载:
void push_back( const T& value );
void push_back( T&& value );
如果您使用第一个,T
(在您的情况下是 Foo
)必须是 "CopyInsertable"。如果用第二个,那肯定是"MoveInsertable".
你的 passFoo2
函数接收到一个 const Foo&&
引用,并且由于它是 const
限定的(见下面的注释),第一个重载是最好的匹配。因此,调用了该重载,这要求您的 class Foo
是可复制的。
注意: 函数 std::move
转换命名对象使其匿名,因此适合由右值引用绑定,但它不t 改变const
资格(它是一个const Foo
移动后的匿名对象)。为此,调用了第一个重载。