偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Visual Studio:優(yōu)化了復(fù)制/移動省略

開發(fā) 前端
當(dāng) C++ 函數(shù)中的 return 關(guān)鍵字后跟非內(nèi)置類型的表達(dá)式時,執(zhí)行該 return 語句會將表達(dá)式的結(jié)果復(fù)制到調(diào)用函數(shù)的返回槽(Return Slot)中。為此,將調(diào)用非內(nèi)置類型的復(fù)制或移動構(gòu)造函數(shù)。然后,作為退出函數(shù)的一部分,將調(diào)用函數(shù)局部變量的析構(gòu)函數(shù),可能包括 return 關(guān)鍵字后面的表達(dá)式中命名的任何變量。

蝎子

為了能發(fā)文,標(biāo)題中的復(fù)制/移動省略是 Copy/Move Elision 的硬翻譯,請各位大大海涵。下文中我會同時使用這兩種術(shù)語。

Visual Studio 中 Copy/Move Elision 的變化

在 Visual Studio 2022 版本 17.4 預(yù)覽版 3 中,我們顯著增加了適用于Copy/Move Elision 情況的數(shù)量,并讓用戶能夠更好地控制是否啟用這些轉(zhuǎn)換。

Copy/Move Elision 是什么?

當(dāng) C++ 函數(shù)中的 return 關(guān)鍵字后跟非內(nèi)置類型的表達(dá)式時,執(zhí)行該 return 語句會將表達(dá)式的結(jié)果復(fù)制到調(diào)用函數(shù)的返回槽(Return Slot)中。為此,將調(diào)用非內(nèi)置類型的復(fù)制或移動構(gòu)造函數(shù)。然后,作為退出函數(shù)的一部分,將調(diào)用函數(shù)局部變量的析構(gòu)函數(shù),可能包括 return 關(guān)鍵字后面的表達(dá)式中命名的任何變量。

C++ 規(guī)范允許編譯器直接在調(diào)用函數(shù)的返回槽中構(gòu)造返回的對象,從而省略作為返回的一部分執(zhí)行的復(fù)制或移動構(gòu)造函數(shù)。與大多數(shù)其他優(yōu)化不同,這種轉(zhuǎn)換允許對程序的輸出產(chǎn)生可觀察的影響 – 即復(fù)制或移動構(gòu)造函數(shù)以及關(guān)聯(lián)的析構(gòu)函數(shù)可以少調(diào)用一次。

Visual Studio 中的 Copy/Move Elision

C++ 標(biāo)準(zhǔn)要求在將返回值初始化為 return 語句的一部分時(例如,當(dāng)返回類型為 Foo 的函數(shù)返回返回 Foo()時),編譯器需要執(zhí)行 Copy/Move Elision。Microsoft Visual C++ 編譯器始終根據(jù)需要對返回語句執(zhí)行 Copy/Move Elision,而不管傳遞給編譯器的標(biāo)志如何。此行為保持不變。

在 Visual Studio 17.4 預(yù)覽版 3 中對可選 Copy/Move Elision 的更改

當(dāng)返回的值為命名變量時,編譯器可能會省略復(fù)制或移動,但不是必需的。C++ 標(biāo)準(zhǔn)仍要求為命名的返回變量定義復(fù)制或移動構(gòu)造函數(shù),即使編譯器在所有情況下都省略了構(gòu)造函數(shù)。在 Visual Studio 2022 版本 17.4 預(yù)覽版 3 之前,當(dāng)禁用優(yōu)化(例如使用 /Od 編譯器標(biāo)志或使用了 #pragma optimize(“”,off))時,編譯器將僅執(zhí)行強制Copy/Move Elision。使用 /O2 標(biāo)志,編譯器將通過簡單的控制流為優(yōu)化的函數(shù)執(zhí)行可選的Copy/Move Elision。

從 Visual Studio 2022 版本 17.4 預(yù)覽版 3 開始,我們?yōu)殚_發(fā)人員提供了與新的 /Zc:nrvo 編譯器標(biāo)志保持一致的選項。默認(rèn)情況下,當(dāng)使用 /O2 標(biāo)志、/permissive- 編譯代碼時,或者在為 /std:c++20 或更高版本進(jìn)行編譯時,將傳遞 /Zc:nrvo 標(biāo)志。通過此標(biāo)志后,將盡可能執(zhí)行復(fù)制和移動省略。我們希望在將來的版本中默認(rèn)啟用 /Zc:nrvo。另外,開發(fā)者還可以使用 /Zc:nrvo- 標(biāo)志顯式禁用可選的Copy/Move Elision。請注意,無法禁用強制型的Copy/Move Elision。

在 Visual Studio 2022 版本 17.4 預(yù)覽版 3 中,當(dāng)使用 /Zc:nrvo、/O2、/permissive-或 /std:c++20 或更高版本的標(biāo)志啟用可選復(fù)制/移動省略時,我們還增加了Copy/Move Elision的位置。

可選 Copy/Move Elision 的示例

可選 Copy/Move Elision 的最簡單示例是以下函數(shù):Foo SimpleReturn() {Foo result;return result;}

在這種情況下,如果傳遞了 /O2 標(biāo)志,則早期版本的 MSVC 編譯器已將結(jié)果的復(fù)制或移動到返回槽中。在 Visual Studio 2022 版本 17.4 預(yù)覽版 3 中,如果傳遞了 /permissive-、/std:c++20 或更高版本或 /Zc:nrvo 標(biāo)志,也會省略復(fù)制或移動,如果傳遞了 /Zc:nrvo- 標(biāo)志,則保留復(fù)制或移動。

從 Visual Studio 2022 版本 17.4 預(yù)覽版 3 開始,如果將 /O2、/permissive-、/std:c++20 或更高版本或 /Zc:nrvo 標(biāo)志傳遞給編譯器,而 /Zc:nrvo- 標(biāo)志未傳遞到編譯器,我們現(xiàn)在在以下其他情況下執(zhí)行復(fù)制/移動省略。

在循環(huán)中返回

Foo ReturnInALoop(int iterations) {for (int i = 0; i < iterations; ++i) {Foo result;if (i == (iterations / 2)) {return result;}}}結(jié)果對象將在循環(huán)的每次迭代開始時正確構(gòu)造,并在每次迭代結(jié)束時銷毀。在返回結(jié)果的迭代中,退出函數(shù)時不會調(diào)用其析構(gòu)函數(shù)。當(dāng)返回的對象超出該函數(shù)的范圍時,函數(shù)的調(diào)用方將銷毀該對象。

在異常處理中返回

Foo ReturnInTryCatch() {
try {
Foo result;
return result;
} catch () {}
}

如果傳遞了 /O2、/permissive-、/std:c++20 或更高版本,或者傳遞了 /Zc:nrvo 標(biāo)志,而 /Zc:nrvo- 標(biāo)志未傳遞,則結(jié)果對象的復(fù)制或移動現(xiàn)在將被省略。我們現(xiàn)在還可以妥善處理更復(fù)雜的情況,例如:

int n;

void throwFirstThreeIterations() {
++n;
if (n <= 3) throw n;
}

Foo ComplexTryCatch()
{
Label1:
Foo result;

try {
throwFirstThreeIterations();
return result;
}
catch() {
goto Label1;
}
}

結(jié)果對象將在調(diào)用方函數(shù)的返回槽中構(gòu)造,并且在成功返回時不會為其調(diào)用復(fù)制/移動構(gòu)造函數(shù)或析構(gòu)函數(shù)。引發(fā)異常時,是否析構(gòu)結(jié)果對象取決于向編譯器傳遞哪些異常處理標(biāo)志。默認(rèn)情況下,不會發(fā)生堆棧展開,因此不會調(diào)用析構(gòu)函數(shù)。但是,如果使用 /EHs、/EHa 或 /EHr 標(biāo)志啟用了堆棧展開異常處理,則 goto Label1 將導(dǎo)致調(diào)用結(jié)果的析構(gòu)函數(shù),因為它跳轉(zhuǎn)到初始化結(jié)果之前。無論哪種方式,當(dāng)再次到達(dá)表達(dá)式 Foo 結(jié)果時,將在返回槽中再次構(gòu)造對象。

復(fù)制具有默認(rèn)參數(shù)的構(gòu)造函數(shù)

現(xiàn)在,我們可以正確檢測到具有默認(rèn)參數(shù)的復(fù)制或移動構(gòu)造函數(shù)仍然是復(fù)制或移動構(gòu)造函數(shù),因此可以在上述情況下被省略。具有默認(rèn)參數(shù)的復(fù)制構(gòu)造函數(shù)如下所示:structStructWithCopyConstructorDefaultParam {int X;

struct
StructWithCopyConstructorDefaultParam {
int X;

StructWithCopyConstructorDefaultParam(int x) : X(x) {}
StructWithCopyConstructorDefaultParam(StructWithCopyConstructorDefaultParam const& original, int defaultParam = 0) :
X(original.X + defaultParam) {
printf(“Copy constructor called.\n”);
}
};

對NRVO的限制

盡管 MSVC 編譯器現(xiàn)在在更多情況下執(zhí)行Copy/Move Elision,但并不總是能夠執(zhí)行它。若要了解為什么會這樣,請考慮以下函數(shù):

Foo WhichShouldIReturn(bool condition) {
Foo resultA;
if (condition) {
Foo resultB;
return resultB;
}
return resultA;
}

復(fù)制省略構(gòu)造要在返回槽中返回的對象,但在這種情況下,應(yīng)在返回槽中構(gòu)造哪個對象?為了在返回結(jié)果A時省略結(jié)果A的副本,必須在返回槽中構(gòu)造它。但是,如果條件為真,則需要在銷毀結(jié)果 A 之前在返回槽中構(gòu)造結(jié)果 B。無法對兩個路徑執(zhí)行復(fù)制省略。

我們目前選擇避免在函數(shù)中的所有路徑上執(zhí)行可選的Copy/Move Elision,如果在任何路徑上它是不可能的的話。但是,對內(nèi)聯(lián)決策、死代碼消除和其他優(yōu)化的更改可能會更改Copy/Move Elision的可能性。因此,編寫依賴于命名變量的Copy/Move Elision的某些行為的代碼是不安全的,除非使用 /Zc:nrvo- 禁用了所有可選的Copy/Move Elision。

只要啟用了堆棧展開異常處理或未引發(fā)異常,仍然可以安全地假定每個構(gòu)造函數(shù)調(diào)用都有匹配的析構(gòu)函數(shù)調(diào)用。

總結(jié)

寫著舊時代的 C++,一直都為如何高性能地返回一個對象發(fā)愁。沒錯,正是在下。

責(zé)任編輯:武曉燕 來源: 今日頭條
相關(guān)推薦

2013-05-17 09:31:53

Windows AzuOffice 365Visual Stud

2009-05-11 09:45:23

Visual Stud復(fù)制代碼ID

2021-10-20 10:12:19

開發(fā)Visual Stud圖標(biāo)

2009-06-23 10:36:32

移動開發(fā)isual Studi

2023-09-05 07:32:22

vscode開源故障

2013-11-14 01:09:35

微軟Visual StudVisual Stud

2009-12-02 09:43:38

Visual Stud

2024-02-27 12:42:38

開發(fā)前端

2019-09-19 08:00:00

Visual StudVisual Stud編程語言

2009-11-10 10:24:28

Visual Stud

2009-11-23 15:41:44

Visual Stud

2009-11-23 17:12:20

Visual Stud

2009-11-10 13:43:37

Visual Stud

2020-08-12 09:53:18

代碼開發(fā)工具

2019-08-13 09:30:50

編程C++后端

2009-11-06 13:25:35

Visual Stud

2009-11-10 12:44:01

Visual Stud

2010-02-22 16:43:33

Visual Stud

2009-11-12 12:42:35

Visual Stud

2010-12-14 09:15:50

Visual Stud
點贊
收藏

51CTO技術(shù)棧公眾號