簡體   English   中英

為什么C ++ 11的move構造函數/賦值運算符不按預期運行

[英]Why do not C++11's move constructor/assignment operator act as expected

#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;
}

我的預期輸出應為:

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

但是,實際輸出為:(C ++編譯器為:Visual Studio 2012)

A()
~A()
~A()

這是VC ++的錯誤嗎? 還是只是我的誤會?

根據此博客文章 ,VC ++ 2012當前實現了N2844 + DR1138 ,但沒有實現N3053 因此,編譯器不會為您隱式生成移動構造函數或賦值運算符。 如果添加顯式默認值並將構造函數移至B ,則將獲得期望的輸出。

Visual C ++ 2012未實現右值引用和移動操作的最終C ++ 11規范(該規范在標准化過程中多次更改)。 您可以在Visual C ++ Team Blog帖子“ Visual C ++ 11中的C ++ 11功能”的 rvalue引用下找到更多信息。

具體來說,在您的示例中,這以兩種方式體現出來:

  • A用戶定義的移動操作的定義不會取消隱式聲明的復制操作。

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

我認為移動構造函數的聲明不會阻止復制ctor的生成。 ...而且似乎編譯器比copy構造函數更喜歡copy構造函數。

實際上,根據12.8 [class.copy]第7段,移動構造函數的存在應防止復制構造函數:

如果類定義未明確聲明一個副本構造函數,則將隱式聲明一個副本構造函數。 如果類定義聲明了move構造函數或move賦值運算符,則隱式聲明的copy構造函數將定義為delete; 否則,將其定義為默認值(8.4)。

但是,移動構造的細節一直更改到過程后期,並且VC ++似乎並沒有實現實際的標准,而是實現了較早的修訂。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM