簡體   English   中英

以下 3 種定義對象的方法是否相同?

[英]Are the following 3 ways to define objects identical?

根據我的理解,以下內容是相同的:

Person p{}; // Case 1
Person p = {}; // Case 1.5

我注意到

Person p = Person{}; // Case 2

產生與上述Case 1Case 1.5相同的跟蹤輸出。

  • 問題 1:將案例 2 與案例 1 或案例 1.5 進行比較,是因為復制省略還是其他原因?

  • 問題2:以下有什么區別?

Person p{};            // Case 1
Person p = Person{};   // Case 2
Person&& p = Person{}; // Case 3

這三個語句在中並不完全相同。

情況 2 需要在 C++17 之前進行移動構造

該語言要求X x = X{}的代碼存在移動構造函數——否則代碼將無法編譯。

例如,使用如下定義的Person類:

class Person{
public:
    ...
    Person(Person&&) = delete;
    ...
};

將無法編譯如下語句:

Person p = Person{}; // Case 2

編譯器資源管理器示例

注意:上面的代碼在及以后的版本中是完全有效的,因為措辭更改允許對象直接在其目標地址中構造,即使在不可移動和不可復制的情況下(這就是人們通常所說的“保證復制省略” ”)。

案例 3 是一個臨時的生命周期延長

第三種情況是構造一個臨時的,它的生命周期通過綁定到一個右值引用來延長。 在某些情況下,臨時對象綁定到右值引用或const左值引用,可以延長其生命周期。 例如,以下兩個構造是等效的,因為它們綁定到臨時的生命周期:

Person&& p3_1 = Person{};
const Person& p3_2 = Person{};

就作用域規則而言,它與任何其他自動變量具有相同的生命周期(例如,它將在作用域末尾調用析構函數,就像Person person{} )。 但是,至少在,構造函數可以完成的操作與Person p2 = Person{}完全不同,因為即使不存在移動構造函數,此代碼也將始終編譯(因為這是引用綁定)。

例如,讓我們考慮一個不可移動、不可復制的類型,如std::mutex C++17 中,編寫以下代碼是有效的:

std::mutex mutex = std::mutex{};

但是在無法編譯的C++11中。 但是,您可以自由編寫:

std::mutex&& mutex = std::mutex{};

它創建一個臨時對象並將其綁定到一個引用,該引用的生命周期將與當時構造的任何范圍變量相同。

編譯器資源管理器上的示例。

注意:故意傳播臨時對象的生命周期通常不是故意的,但在 C++17 之前,這是使用不可移動對象實現幾乎總是自動的語法的唯一方法。 例如,上面可以重寫: auto&& mutex = std::mutex{}

- 關於構造將如何發生,以及構造變量的行為方式; 沒有關於變量的類型。

編譯器在任何這些情況下都不使用賦值,即它只有您的程序默認構造。 您可以使用此代碼來驗證:

#include <iostream>

struct Person {
    Person& operator=(Person&) {
       std::cout << "Assignment: operator=(Person&)\n";  return *this; 
    }
    Person& operator=(Person&&) { 
       std::cout << "Move assignment: operator=(Person&&)\n";  return *this; 
    }
    Person(const Person&) { std::cout << "Copy ctor: Person(Person&)\n"; }
    Person(Person&&) { std::cout << "Move ctor: Person(Person&&)\n"; }
    Person() { std::cout << "Default ctor: Person()\n"; }
};

int main() {
    std::cout << "P1:\n";
    Person p1{};
    std::cout << "Address of P1: " << &p1 << '\n';
    std::cout << "P2:\n";
    Person p2 = Person{};
    std::cout << "Address of P2: " << &p2 << '\n';
    std::cout << "P3:\n";
    Person&& p3 = Person{};
    std::cout << "Address of P3: " << &p3 << '\n';
}

GodBolt查看

第三個語句的行為讓我有點驚訝。 我實際上雖然編譯器可能會直接拒絕它。 無論如何 -請不要像這樣聲明右值引用 這讓讀者感到困惑——甚至對我來說也是如此,而且幾乎可以肯定這不是你想要做的。 我確信p3行為就像一個右值引用; 但是 - 實際上並非如此,顯然:盡管具有Person&&類型,但在傳遞給函數時,它的行為類似於左值引用。

暫無
暫無

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

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