自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

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

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

蝎子

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

Visual Studio 中 Copy/Move Elision 的變化

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

Copy/Move Elision 是什么?

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

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

Visual Studio 中的 Copy/Move Elision

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

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

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

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

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

可選 Copy/Move Elision 的示例

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

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

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

在循環(huán)中返回

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

在異常處理中返回

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

如果傳遞了 /O2、/permissive-、/std:c++20 或更高版本,或者傳遞了 /Zc:nrvo 標(biāo)志,而 /Zc:nrvo- 標(biāo)志未傳遞,則結(jié)果對(duì)象的復(fù)制或移動(dòng)現(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é)果對(duì)象將在調(diào)用方函數(shù)的返回槽中構(gòu)造,并且在成功返回時(shí)不會(huì)為其調(diào)用復(fù)制/移動(dòng)構(gòu)造函數(shù)或析構(gòu)函數(shù)。引發(fā)異常時(shí),是否析構(gòu)結(jié)果對(duì)象取決于向編譯器傳遞哪些異常處理標(biāo)志。默認(rèn)情況下,不會(huì)發(fā)生堆棧展開(kāi),因此不會(huì)調(diào)用析構(gòu)函數(shù)。但是,如果使用 /EHs、/EHa 或 /EHr 標(biāo)志啟用了堆棧展開(kāi)異常處理,則 goto Label1 將導(dǎo)致調(diào)用結(jié)果的析構(gòu)函數(shù),因?yàn)樗D(zhuǎn)到初始化結(jié)果之前。無(wú)論哪種方式,當(dāng)再次到達(dá)表達(dá)式 Foo 結(jié)果時(shí),將在返回槽中再次構(gòu)造對(duì)象。

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

現(xiàn)在,我們可以正確檢測(cè)到具有默認(rèn)參數(shù)的復(fù)制或移動(dòng)構(gòu)造函數(shù)仍然是復(fù)制或移動(dòng)構(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”);
}
};

對(duì)NRVO的限制

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

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

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

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

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

總結(jié)

寫(xiě)著舊時(shí)代的 C++,一直都為如何高性能地返回一個(gè)對(duì)象發(fā)愁。沒(méi)錯(cuò),正是在下。

責(zé)任編輯:武曉燕 來(lái)源: 今日頭條
相關(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

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

2009-06-23 10:36:32

移動(dòng)開(kāi)發(fā)isual Studi

2013-11-14 01:09:35

微軟Visual StudVisual Stud

2023-09-05 07:32:22

vscode開(kāi)源故障

2019-09-19 08:00:00

Visual StudVisual Stud編程語(yǔ)言

2009-12-02 09:43:38

Visual Stud

2024-02-27 12:42:38

開(kāi)發(fā)前端

2009-11-10 13:43:37

Visual 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

2019-08-13 09:30:50

編程C++后端

2020-08-12 09:53:18

代碼開(kāi)發(fā)工具

2009-11-06 13:54:09

Visual Stud

2009-11-06 16:36:37

Visual Stud

2013-11-13 10:07:26

Visual Stud微軟

2009-11-12 09:15:33

Visual Stud

2009-12-03 17:54:32

Visual Stud
點(diǎn)贊
收藏

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