[英]Are the following 3 ways to define objects identical?
根據我的理解,以下內容是相同的:
Person p{}; // Case 1
Person p = {}; // Case 1.5
我注意到
Person p = Person{}; // Case 2
產生與上述Case 1
和Case 1.5
相同的跟蹤輸出。
問題 1:將案例 2 與案例 1 或案例 1.5 進行比較,是因為復制省略還是其他原因?
問題2:以下有什么區別?
Person p{}; // Case 1
Person p = Person{}; // Case 2
Person&& p = Person{}; // Case 3
這三個語句在c++11中並不完全相同。
該語言要求X x = X{}
的代碼存在移動構造函數——否則代碼將無法編譯。
例如,使用如下定義的Person
類:
class Person{
public:
...
Person(Person&&) = delete;
...
};
將無法編譯如下語句:
Person p = Person{}; // Case 2
編譯器資源管理器示例
注意:上面的代碼在c++17及以后的版本中是完全有效的,因為措辭更改允許對象直接在其目標地址中構造,即使在不可移動和不可復制的情況下(這就是人們通常所說的“保證復制省略” ”)。
第三種情況是構造一個臨時的,它的生命周期通過綁定到一個右值引用來延長。 在某些情況下,臨時對象綁定到右值引用或const
左值引用,可以延長其生命周期。 例如,以下兩個構造是等效的,因為它們綁定到臨時的生命周期:
Person&& p3_1 = Person{};
const Person& p3_2 = Person{};
就作用域規則而言,它與任何其他自動變量具有相同的生命周期(例如,它將在作用域末尾調用析構函數,就像Person person{}
)。 但是,至少在c++11 中,構造函數可以完成的操作與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';
}
第三個語句的行為讓我有點驚訝。 我實際上雖然編譯器可能會直接拒絕它。 無論如何 -請不要像這樣聲明右值引用。 這讓讀者感到困惑——甚至對我來說也是如此,而且幾乎可以肯定這不是你想要做的。 我確信p3
行為就像一個右值引用; 但是 - 實際上並非如此,顯然:盡管具有Person&&
類型,但在傳遞給函數時,它的行為將類似於左值引用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.