请考虑以下代码段:
#include <utility>
struct foo
{
foo()
{
}
foo(foo&& other)
{
std::swap(*this, other);
}
};
int main(int argc, char** argv)
{
foo f(std::move(foo()));
}
它在VS2013中导致无限递归,但无法用g ++ / clang编译,错误operator=
被删除(这是有道理的):
In file included from /usr/local/include/c++/5.3.0/bits/stl_pair.h:59:0,
from /usr/local/include/c++/5.3.0/utility:70,
from main.cpp:1:
/usr/local/include/c++/5.3.0/bits/move.h: In instantiation of 'void std::swap(_Tp&, _Tp&) [with _Tp = foo]':
main.cpp:11:26: required from here
/usr/local/include/c++/5.3.0/bits/move.h:186:11: error: use of deleted function 'foo& foo::operator=(const foo&)'
__a = _GLIBCXX_MOVE(__b);
^
main.cpp:3:12: note: 'foo& foo::operator=(const foo&)' is implicitly declared as deleted because 'foo' declares a move constructor or move assignment operator
struct foo
^
In file included from /usr/local/include/c++/5.3.0/bits/stl_pair.h:59:0,
from /usr/local/include/c++/5.3.0/utility:70,
from main.cpp:1:
/usr/local/include/c++/5.3.0/bits/move.h:187:11: error: use of deleted function 'foo& foo::operator=(const foo&)'
__b = _GLIBCXX_MOVE(__tmp);
^
我认为这是一个VS错误。但标准是否对如何实施std::swap
施加了任何规则?我的意思是这只是VS中的一个糟糕的实现还是违反了标准?
答案 0 :(得分:2)
是的,这段代码不应该编译,因为根据C ++ 14标准草案N4140 [utility.swap] / 2:
要求:类型
T
应为MoveConstructible
(表20)和MoveAssignable
(表22)。
C ++ 11包含相同的要求。
所以这确实是VS2013中的一个错误,它实际上是在VS2015中修复的。
然而,在添加这样的移动赋值运算符之后:
foo& operator=(foo&& other) = default;
你将在GCC,Clang和VS2015(DEMO)获得无限递归。
可以很容易地猜到,因为swap()
需要MoveConstructible
和MoveAssignable
,所以它使用移动构造函数和/或移动赋值运算符,因此通过调用{{}来实现它们绝对是非法的1}}表示swap()
和参数。