2012-09-28 75 views
8
#include <iostream> 

using namespace std; 

struct A 
{ 
    A() 
    { 
     cout << "A()" << endl; 
    } 

    ~A() 
    { 
     cout << "~A()" << endl; 
    } 

    A(A&&) 
    { 
     cout << "A(A&&)" << endl; 
    } 

    A& operator =(A&&) 
    { 
     cout << "A& operator =(A&&)" << endl; 
     return *this; 
    } 
}; 

struct B 
{ 
    // According to the C++11, the move ctor/assignment operator 
    // should be implicitly declared and defined. The move ctor 
    // /assignment operator should implicitly call class A's move 
    // ctor/assignment operator to move member a. 
    A a; 
}; 

B f() 
{ 
    B b; 

    // The compiler knows b is a temporary object, so implicitly 
    // defined move ctor/assignment operator of class B should be 
    // called here. Which will cause A's move ctor is called. 
    return b; 
} 

int main() 
{ 
    f(); 
    return 0; 
} 

我的預期產出應不C++ 11的移動構造函數/賦值運算符的行爲:爲什麼預期

A() 
A(A&&) 
~A() 
~A() 

然而,實際的輸出是:(C++編譯器是:的Visual Studio 2012 )

A() 
~A() 
~A() 

這是VC++的bug嗎?或者只是我的誤解?

+1

爲什麼你期望'A'的移動賦值操作符被調用? – Praetorian

+0

@Prætorian:當RVO未被應用時,C++ 11說'return b'應該將'b'移到返回值中。也許Visual Studio 2012只是不正確地實現C++ 11? –

+2

@KevinBallard是的,'b'應該移動。但是,這會導致調用'A'的move *構造函數*,而不是移動*賦值運算符*。 – Praetorian

回答

14

根據this blog post,VC++ 2012目前實現了N2844 + DR1138,但不是N3053。因此,編譯器爲而不是隱式地爲您生成移動構造函數或賦值運算符。如果您添加明確的默認值並將構造函數移動到B那麼您將得到您期望的輸出。

+5

聽到這個很遺憾。我認爲這是C++ 11的一個非常基本的特性。 – xmllmx

+1

可惜,這使得'升級'來移動語義,向每個可移動類添加移動構造函數,然後添加到所包含的類等是不切實際的。 – Zero

+0

@零:完全同意。作爲一線希望,如果現在不做任何事情,它們並沒有比以前更糟,但是當編譯器最終得到改進時,就像其他人早些時候做的那樣,他們會免費獲得這些改進。 ; - ] – ildjarn

1

我不認爲複製ctor的生成是由移動構造函數的聲明阻止的。 ...似乎編譯器喜歡複製構造函數的移動構造函數。

實際上,根據12.8 class.copy]段7此舉構造存在應防止拷貝構造函數:

如果類定義不明確聲明拷貝構造函數,一個是隱式聲明。如果類定義聲明瞭移動構造函數或移動賦值操作符,則隱式聲明的拷貝構造函數被定義爲刪除;否則,它被定義爲默認(8.4)。

但是,移動構造的細節直到後期才改變,看起來VC++並沒有實現實際的標準,而是一個較早的版本。

+2

如果類具有用戶聲明的移動構造函數或移動賦值運算符(因爲Visual C++沒有完全實現最終規範,所以不會在這裏刪除),隱式聲明的拷貝構造函數_應該被聲明爲刪除。 –

+0

@JamesMcNellis是的,我想我記得早期版本的標準,並找到細節後,我相應地更新了答案。 –

7

Visual C++ 2012沒有爲右值引用和移動操作實現最終的C++ 11規範(規範在標準化過程中多次更改)。您可以在Visual C++團隊博客文章中找到更多信息,"C++11 Features in Visual C++ 11"右值引用

在您的例子而言,這表現在兩個方面:

  • A用戶定義的移動操作的定義不抑制隱含聲明的複製操作。

  • 對於B沒有隱式定義的移動操作。