簡體   English   中英

未調用移動構造函數和復制構造函數

[英]Move-ctor and copy-ctor not called

讓我們以以下 C++ 示例為例:

#include <iostream>

struct X
{
  std::string s;

  X() : s("X") { }

  X(const X& other) : s{other.s} { std::cout << "cpy-ctor\n"; }

  X(X&& o): s{o.s} { o.s = ""; std::cout << "move-ctor\n"; }

  X& operator=(const X& other) {
    std::cout << "cpy-assigned\n";
    s = other.s;
    return *this;
  }

  X& operator=(X&& other) {
    if (this != &other) {
      s = other.s;
      other.s = "";
    }
    std::cout << "move assigned\n";
    return *this;
  }
};

X f(X x) {
  std::cout << "f: ";
  return x;
}

X g() {
  std::cout << "g: ";
  X x;
  return x;
}

int main() {
  X x;
  X y;
  x = f(X());
  y = g();
}

如果我用 gcc 4.8.2 編譯它,我有以下結果:

f: move-ctor
move assigned
g: move assigned

我不明白為什么在調用 g 函數時不調用復制構造函數。

我只是想了解何時調用復制或移動構造函數。

雖然你是正確的,以確定有,在邏輯上,復制/局部變量的移動x從內g()返回時,C ++的一個非常有用的功能是它可以的Elid(即跳過)在許多情況下,這種操作,即使復制/移動會產生副作用 這是其中一種情況。 執行時,這稱為命名返回值優化

可以說它不如我們有移動語義之前有用,但它仍然很好。 事實上, C++17 在某些(選擇)情況下強制執行

在 C++ 中,所有表達式都是:

  • 左值
  • 右值

構造對象

- 左值

Y x{};
Y y{x}; // copy constructor, x is an lvalue

- 右值 - RVO

使用 RVO,默認情況下由 gcc 啟用。 這省略了使用復制構造函數,而是將對象構造一次。

X g()
{
  X x {}; 
  x.value = 10;
  return x;
}

X y {g()}; // X constructor get's called only once to create "y". Also 
           // y is passed a a reference to g() where y.value = 10. 
           // No copy/move constructor for optimization "as if" rule

- 純右值 - 無 RVO

如果沒有 RVO,在這種情況下取​​決於。 如果移動構造函數被顯式或隱式刪除,那么它將調用復制構造函數

復制構造函數

struct X { X(const X&) {}}; // implicitly deletes move constructor 
                            // and move assignment, see rule of 5

X g()
{
  return X{}; // returns a prvalue
}

X y {g()}; // prvalue gets converted to xvalue, 
           // "temporary materialization", where the xvalue has an 
           // identity where members can be copied from. The xvalue
           // binds to lvalue reference, the one from copy constructor
           // argument

移動構造函數

X { X(X&&) {}}; // explicitly declared move constructor

X g()
{
  return X{}; // returns a prvalue
}

X y {g()}; // prvalue gets converted to xvalue, 
           // "temporary materialization", where the xvalue has an
           // identity where members can be moved from. The xvalue 
           // binds to rvalue reference, the one from move constructor 
           // argument

- 值

X x {};
X y {std::move(x)}; // std::move returns an xvalue, where if move 
                    // constructor is declared will call it, other wise 
                    // copy constructor, similar to explained above for 
                    // prvalue.

復制/移動分配

- 左值

X x{};
X y{};

x = y; // call copy assignment operator since y is an lvalue.

- 右值

如果顯式或隱式刪除了移動賦值,則它將調用復制賦值運算符。

復制作業

struct X{ X& operator=(const X&); } // implicilty deletes move 
                                    // constructor and move assignment,
                                    // see rule of 5

X g()
{
  return X{}; // returns a prvalue
}

x = g(); // prvalue gets converted to xvalue, 
       // "temporary materialization", where the xvalue has an identity 
       // where members can be copied from. The xvalue binds to lvalue 
       // reference, the one from copy assignment operator argument

移動分配

struct X{ X& operator=(X&&); } // explicitly declared move assignment        operator

X g()
{
  return X{}; // returns a prvalue
}

x = g(); // prvalue gets converted to xvalue, 
       // "temporary materialization", where the xvalue has an identity 
       // where members can be moved from. The xvalue binds to rvalue 
       // reference, the one from move assignment operator argument

- 值

X x {};
X y {};

x = std::move(x); // std::move returns an xvalue, where if move
                  // assignment is declared will call it, other 
                  // wise copy assignment, similar to explained 
                  // above for prvalue. 

當您使用另一個相同類型的對象實例化一個對象時,將調用復制構造函數。

例如:

X x;
X y(x);

代碼中的最后一行將從函數返回的值分配給已構造的對象。 這是通過移動分配完成的。

暫無
暫無

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

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