2017-05-29 29 views
3

如果我理解正確的話,從C++ 17日開始,該代碼現在要求任何副本將完成:確保副本elision與函數參數一起工作嗎?

Foo myfunc(void) { 
    return Foo(); 
} 

auto foo = myfunc(); // no copy 

是否也適用於函數的參數?下面的代碼會將副本優化掉嗎?

Foo myfunc(Foo foo) { 
    return foo; 
} 

auto foo = myfunc(Foo()); // will there be copies? 
+7

注意:您正在使用C++ 17,那麼如果函數不帶參數,爲什麼還要放置'void'? – Rakete1111

+1

@ Rakete1111是否有任何標準,需要把這個'void'?必須早在我的時間之前用C++ – user463035818

+0

@ tobi303我不知道。可能在C++被標準化之前,當它仍然基於C但是我不知道。 – Rakete1111

回答

2

在C++ 17中,prvalues(「匿名臨時對象」)不再是對象。相反,它們是關於如何構建對象的說明。

他們可以從他們的施工說明中實例化臨時工,但由於沒有對象那裏有,所以沒有複製/移動的構造要刪除。

Foo myfunc(Foo foo) { 
    return foo; 
} 

所以在這裏,函數參數foo移入的myfunc的prvalue返回值。您可以將此概念視爲「myfunc返回有關如何生成Foo的說明」。如果這些指令是您的程序「未使用」,則會自動實例化一個臨時指令並使用這些指令。

auto foo = myfunc(Foo()); 

所以這裏Foo()是一個prvalue。它說「使用()構造函數構造Foo」。然後用它來構造myfunc的參數。沒有發生刪除,沒有複製構造函數或移動構造函數被調用,只是()

然後發生在myfunc裏面的東西。

myfunc返回類型Foo的預估值。這個prvalue(又名施工指令)用於構造局部變量auto foo

因此,這裏發生的是Foo通過()構建,然後移動到auto foo。我知道(我可能是錯的,我沒有這裏的標準章節和經文),C++ 14和C++ 17都不支持函數參數的刪除。但是,在return func_arg;上下文中使用時,它們將被隱式移動。

1

是的,沒有。引述cppreference

在下列情況下,編譯器必須省略禁止複製和類對象的施工MOVE- [...]:

  • 在初始化中,如果初始化表達式是一個prvalue,源類型的cv不合格版本與目的類的類相同,初始化表達式用於初始化目標對象

  • 在函數調用中,如果返回的操作數聲明是一個prv alue並且函數的返回類型與該prvalue的類型相同。

所以,在你的第二個片段只有一個默認的構造函數將被調用。首先,foomyFuncFoo()(1默認構造)初始化,這是一個prvalue。這意味着它將被消除(見第1點)。

接下來,myFunc返回foo的副本,該副本不能被忽略foo不是prvalue(點2)。所以,有一個舉動,因爲foo是一個xvalue。但實際的回報價值是一個價值,因爲它是foo的新實例(在myFunc中),並且由於第一點它被省略了。

總之,標準保證了一種默認的結構和一次移動。不能再有了。但是,編譯器可能完全忽略了唯一的舉動。

+2

複製?我認爲你的意思是移動。在C++標準中的構造是指與if-if規則不同的東西;你的意思是使用eliding嗎? – Yakk

+0

而C++ 17使某些事物不是對象;沒有省略移動/複製發生。 – Yakk

+0

@Yakk是的,你是對的! :)但我不明白你關於非對象的觀點。你能否詳細說明一下? – Rakete1111

相關問題