2016-03-03 49 views
1

考慮這個片段:的std ::交換導致無限遞歸在VS 2013

#include <utility> 

struct foo 
{ 
    foo() 
    { 
    } 

    foo(foo&& other) 
    { 
     std::swap(*this, other); 
    } 
}; 

int main(int argc, char** argv) 
{ 
    foo f(std::move(foo())); 
} 

它會導致在VS2013無限遞歸,但無法與編譯克++ /鐺有錯誤該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

「swap」通過臨時對象移動構建似乎是合理的。 'foo(foo &&)'更常用於將_members_與它的參數交換。即foo(foo && other){swap(member,other.member); }'等 –

+0

@TobySpeight是的我知道這不是執行移動構造函數的規範方式 - 我通常也會選擇你描述的方式,但是當我在VS中偶然發現這種行爲時,我很驚訝:D –

回答

2

是的,這個代碼不應該編譯,因爲根據C++ 14標準草案N4140 [utility.swap]/2:

需要:類型TMoveConstructible(表20)和MoveAssignable(表22)。

C++ 11包含相同的要求。

所以這確實是VS2013中的一個錯誤,它實際上在VS2015中是固定的。

然而,增加移動賦值運算符這樣的後:

foo& operator=(foo&& other) = default; 

你會得到GCC,鏘和VS2015(DEMO)無限遞歸。

人們可以很容易猜到,既然swap()需要MoveConstructibleMoveAssignable,它採用移動的構造和/或內部移動賦值運算符,所以它肯定是非法通過呼叫swap()this和參數來實現它們。