c++ 投擲活動物體
我注意到,當丟擲的型別是可移動的時候,MSVC和g如何處理臨時異常物件的建立,這一點略有不同.狩獵這些引起了額外的問題.
在進一步之前,這裡是我的問題的核心:在複製/移動精靈的缺點中,標準人員是否說明如何建立臨時異常物件?目前,我能做的最好的是從15.1 / 3以下引用:
A throw-expression initializes a temporary object, called the exception object, the type of which is determined by removing any top-level cv-qualifiers from the static type of the operand of throw and adjusting the type from “array of T” or “function returning T” to “pointer to T” or “pointer to function returning T”, respectively.
我猜這個答案被埋在別的語言的某個地方,定義了一個表示式的型別,以及物件的初始化,但是我沒有運氣拼接在一起.當丟擲一個物件時,異常物件是否得到(a)複製構造,(b)適當地移動構造,否則複製構造,或者(c)以實現定義的方式初始化?
請考慮以下程式碼:
#include <iostream> using std::cout; using std::cin; using std::endl; struct Blob { Blob() { cout << "C" << endl; } Blob(const Blob&) { cout << "c" << endl; } Blob(Blob&&) { cout << "m" << endl; } Blob& operator =(const Blob&) { cout << "=" << endl; return *this; } Blob& operator =(Blob&&) { cout << "=m" << endl; return *this; } ~Blob() { cout << "~" << endl; } int i; }; int main() { try { cout << "Throw directly: " << endl; throw Blob(); } catch(const Blob& e) { cout << "caught: " << &e << endl; } try { cout << "Throw with object about to die anyhow" << endl; Blob b; throw b; } catch(const Blob& e) { cout << "caught: " << &e << endl;} { cout << "Throw with object not about to die anyhow (enter non-zero integer)" << endl; Blob b; int tmp; cin >> tmp; //Just trying to keep optimizers from removing dead code try { if(tmp) throw b; cout << "Test is worthless if you enter '0' silly" << endl; } catch(const Blob& e) { cout << "caught: " << &e << endl;} b.i = tmp; cout << b.i << endl; } }
這是在ofollow,noindex" target="_blank">ideone 上重新建立的.正如你所希望看到的,gcc通過ideone在第一種情況下建立了Blob物件,並在第二種情況下移動.結果總結如下,指標值替換為識別符號.
Throw directly: C {A} caught: {A} ~ {A} Throw with object about to die anyhow C {A} m {B} <- {A} ~ {A} caught: {B} ~ {B} Throw with object not about to die anyhow (enter non-zero integer) C {A} m {B} <- {A} caught: {B} ~ {B} 2 ~ {A}
在MSVC2010中相同的程式碼,無論優化設定如何,結果是一樣的,除了兩個動作是副本.這是最初引起我注意的區別.
我假設的第一個測試是罰款;其經典版影印.
在第二個測試中,gcc的行為方式與我預期的一樣.臨時Blob被視為一個x值,異常物件由它移動構造.但是我不知道編譯器是否需要識別原始的Blob是否到期;如果不是,則MSVC在複製時正常執行.因此,我的原始問題:標準授權在這裡發生了什麼,還是隻是執行定義的行為繼承異常處理的一部分?
第三個測試正好相反:MSVC行為我的直覺要求. gcc選擇從b移動,但是b仍然存在,這在我處理丟擲的異常之後繼續使用它的事實證明了這一點.顯然,在這個微不足道的例子中,移動或複製對b本身沒有任何影響,但是當考慮過載解析度時,肯定不允許編譯器檢視.
顯然,複製/移動檢測的存在使得這個簡單的測試很難推廣,但更大的問題是,編譯器可能不會簡單[特別是在第三次測試的gcc和一般的MSVC的情況下].
注意這完全是為了學術目的;我幾乎不會丟擲任何東西,除了一個臨時的,這兩個編譯器構造在任何地方,我相當確定行為是允許的.
移動行為符合案例2,但不符合案例3.參見12.8 [class.copy] / p31:
When certain criteria are met, an
implementation is allowed to omit the
copy/move construction of a class
object, even if the copy/move
constructor and/or destructor for the
object have side effects. …
…
-
in a throw-expression, when the operand is the name of a non-volatile
automatic object (other than a
function or catch-clause parameter)
whose scope does not extend beyond the
end of the innermost enclosing
try-block (if there is one), the
copy/move operation from the operand
to the exception object (15.1) can be
omitted by constructing the automatic
object directly into the exception
object
上面沒有定義何時可以隱式地移動物件.但是它確實定義了複製/移動檢查是否合法.當隱含的移動是合法的時候,你必須參考同一節中的第32段:
32 When the criteria for elision of acopy operation are met or would be metsave for the fact that the sourceobject is a function parameter, andthe object to be copied is designatedby an lvalue, overload resolution …
本段解釋說,當複製/移動檢測是合法的時候,過載解決會發生兩次:
>首先假設lvalue是決定什麼建構函式被呼叫或被刪除的值.
>如果1)失敗,則以引數作為左值重複過載解析.
這具有從最差到最差產生移動語義層次結構的效果:
>如果你可以去施工,就這樣做.
>否則,如果你可以移動物件,這樣做.
>否則可以將物件複製出來,這樣做.
>否則發出診斷.
請注意,這些本質上是與普通返回本地堆疊物件相同的規則.
http://stackoverflow.com/questions/6352438/throwing-movable-objects
本站文章除註明轉載外,均為本站原創或編譯
轉載請明顯位置註明出處:c++投擲活動物體