簡體   English   中英

C ++ 11 - 我丟失了移動/復制任務

[英]C++11 - I lost a move/copy assignment

我在另一個問題上發布了這個代碼,但我對此有了新的疑問:

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class X
{
    public:

    std::vector<double> data;

    // Constructor1
    X():
        data(100000) // lots of data
    {
        cout << "X default constructor called";
    }

    // Constructor2
    X(X const& other): // copy constructor
        data(other.data)   // duplicate all that data
    {
        cout << "X copy constructor called";
    }

    // Constructor3
    X(X&& other):  // move constructor
        data(std::move(other.data)) // move the data: no copies
    {
        cout << "X move constructor called";
    }

    X& operator=(X const& other) // copy-assignment
    {
        cout << "X copy assignment called";
        data=other.data; // copy all the data
        return *this;
    }

    X& operator=(X && other) // move-assignment
    {
        cout << "X move assignment called";
        data=std::move(other.data); // move the data: no copies
        return *this;
    }

};

class X2
{
    public:

    std::vector<double> data;

    // Constructor1
    X2():
        data(100000) // lots of data
    {}

    // Constructor2
    X2(X const& other): // copy constructor
        data(other.data)   // duplicate all that data
    {}

    X2& operator=(X const& other) // copy-assignment
    {
        data=other.data; // copy all the data
        return *this;
    }
};

X make_x()
{
    X myNewObject; // Il normale costruttore viene chiamato qui
    myNewObject.data.push_back(22);
    return myNewObject; // Si crea un oggetto temporaneo prima di ritornare con il move constructor perchè myNewObject dev'essere distrutto
}


int main()
{
    X x1 = make_x(); // x1 has a move constructor


    X2 x2 = make_x(); // x2 hasn't a move constructor
}

在main()行中,我希望調用移動賦值和復制賦值......但它們不會!

MSVC2012輸出是:

X默認構造函數名為X move constructor,名為X默認構造函數,名為X move constructor,名為

而g ++就是

X默認構造函數調用X默認構造函數調用

http://liveworkspace.org/code/220erd $ 2

作業在哪里? 我認為第一個main()行將調用移動賦值,第二個main()行將調用復制賦值

// Constructor2
X2(X const& other): // copy constructor
    data(other.data)   // duplicate all that data
{}

X2& operator=(X const& other) // copy-assignment
{
    data=other.data; // copy all the data
    return *this;
}

首先,這些不是X2的復制構造函數和復制賦值運算符,因為它們接受X類型的參數。 第一種實際上稱為轉換構造函數,因為它可以從X轉換為X2

int x = 5;

這不是5分配給x ; 它是x與正被初始化5 初始化雖然看起來很相似,但與賦值不同。 實際上,代碼中根本不會發生任何賦值,因此不會使用移動或復制賦值運算符。

我們可以看看你給出的每個編譯器實際上在做什么:

  1. MSVC

    首先, myNewObject在創建make_x 這打印出X default constructor called 然后return myNewObject; 將復制視為返回值作為移動優先,發現有一個移動構造函數,並調用它。

    當滿足或將滿足復制操作的省略標准時,除了源對象是函數參數這一事實,並且要復制的對象由左值指定,重載決策選擇復制的構造函數是首先執行,好像對象是由右值指定的。

    然后將返回值復制到x1 但是,這個副本顯然已被刪除,因為我們看不到X copy constructor called output的X copy constructor called

    當一個未綁定到引用(12.2)的臨時類對象被復制/移動到具有相同cv-nonqualified類型的類對象時,可以通過將臨時對象直接構造到目標中來省略復制/移動操作省略的復制/移動

    其次,另一個myNewObject在第二次調用創建make_x 這再次打印出X default constructor called 然后在return myNewObject時發生相同的移動。 從返回值構造x2不會輸出任何內容,因為其帶有X構造函數不會執行任何輸出。

  2. GCC

    首先, myNewObject在創建make_x ,就像MSVC。 這打印出X default constructor called

    現在,GCC進行了MSVC沒有做的額外優化。 它意識到它可能不會費心從myNewObject移動到返回值,而只是直接在返回值的位置構造它:

    在具有類返回類型的函數的return語句中,當表達式是具有與函數返回類型相同的cvunqualified類型的非易失性自動對象(函數或catch子句參數除外)的名稱時,副本通過將自動對象直接構造到函數的返回值中,可以省略/ move操作

    然后,如在MSVC中那樣執行從臨時對象構造x1導致的相同省略。

    make_x的第二次調用以與第一次調用完全相同的方式發生,除了現在x2由采用X的轉換構造函數構造。 當然,這不會產生任何結果。

您正在查看命名返回值優化 NRVO的效果。 以下代碼

X f()
{
  X tmp;
  // ...
  return tmp;
}

可以完全刪除臨時並在函數調用者的返回槽中構造它。 在您的示例中,效果就像函數內聯並直接構造x1x2

如果你想看到作業,你可以寫:

X x1;
x1 = make_x();

暫無
暫無

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

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