2013-06-05 15 views
19

最近、私は自分のふるまいを理解するために、評価額を「再生」しました。ほとんどの結果は私を驚かせることはありませんでしたが、私はローカル変数をスローすると、移動コンストラクタが呼び出されることがわかりました。なぜローカル変数呼び出しがコンストラクタを移動するのですか?

これまでは、移動セマンティクス規則の目的は、コンパイラが(一時オブジェクトの場合のように)それ以上使用されないことを検出できる場合にのみ、オブジェクトが移動して無効になることを保証することであると考えました。ユーザーはそれを使用しないことを約束します(std :: moveのように)。

ただし、次のコードではこの条件は保持されず、変数はまだ移動されています(少なくともg ++ 4.7.3では)。

なぜですか?

#include <iostream> 
#include <string> 
using namespace std; 

int main() { 
    string s="blabla"; 
    try { 
     throw s; 
    } 
    catch(...) { 
     cout<<"Exception!\n"; 
    } 
    cout<<s; //prints nothing 
} 
+3

もしそうなら、gccのバグのようです。 –

+0

@kbok:あなたが正しいです、私は私の答えを削除しました(私はここにあなたのコメントに答えています)。私はどういうわけか 's'が' try'ブロックの中で宣言されていると思っていました。申し訳ありませんすべて –

+0

http://gcc.gnu.org/bugzillaに報告してください - ありがとう! –

答えて

5

この場合、スローされた変数は後で参照されるため、おそらくコンパイラのバグです。

一般に、移動を呼び出す場合、throwは、移動することは概念的にはreturnと同じです。与えられた点(throwまたはreturn)の後で変数を参照できないことがわかっているときは、自動的に移動を呼び出すとよいでしょう。

+0

ありがとうございます。私の直感がgccよりも優れていることを知ることは、常に良いことです... – asaelr

7

C++標準は述べています(15.1.3):

は(8.5、12.8)一時オブジェクトは、例外オブジェクトと呼ばれる例外 コピー初期化を投げます。一時変数は左辺値であり、一致するハンドラ(15.3)で指定された変数を初期化するために使用されます。

この段落はここに(12.8.31)も関連する可能性がある:特定の条件が満たされると

実装はコンストラクタが選択された場合でも、クラスオブジェクトのコピー/移動工事を省略することが許可されていますコピー/移動操作および/またはオブジェクトのデストラクタには副作用があります。そのような場合、実装は、省略されたコピー/移動操作のソースとターゲットを、同じオブジェクトを参照する2つの異なる方法として扱い、そのオブジェクトの破棄は、2つのオブジェクトが最適化せずに破壊されました。コピーの省略と呼ばれるコピー/移動操作のこのエリジオンは、(複数のコピーを排除するために組み合わせることができる)は、以下の状況で許可されている:

(...)

- 投入式でオペランドが不揮発性の自動オブジェクト(関数またはキャッチ節パラメータ以外)の名前である場合 スコープが最も内側にあるtry-block(存在する場合)の終わりを超えて拡張されない場合、自動オブジェクトを例外オブジェクトに直接組み込むことにより、オペランドから例外オブジェクト(15.1)へのコピー/移動操作を省略することができます。
それは確かにGCCのバグのように見える

Exception! 
blabla 

は、Visual Studioの2012年に効果をチェック。

+0

もしそうなら、 'throw'が' try'ブロックの中にいなくても、コンパイラはmoveコンストラクタを呼び出すことができません。 – asaelr

+0

@asaelr:更新された引用情報から、スローされるオブジェクトは、戻り値と同じように、コピー、移動、または構築される可能性があります。 –

+0

@asaelrです。しかし、この特定のケースでは、変数が後でtry-blockから使用されるため、move-ctorが正しくコールされません。 – Spook

関連する問題