std :: swap在VS 2013中导致无限递归

时间:2016-03-03 19:26:52

标签: c++ c++11 recursion

请考虑以下代码段:

#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中的一个糟糕的实现还是违反了标准?

1 个答案:

答案 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()需要MoveConstructibleMoveAssignable,所以它使用移动构造函数和/或移动赋值运算符,因此通过调用{{}来实现它们绝对是非法的1}}表示swap()和参数。