2012-05-10 14 views
3

私は奇妙なセグメンテーションに遭遇しました。原因は、実際にバグに私を導いたが、セグメンテーションフォールトがここで発生している理由私はまだ理解していない...コードは次のとおりです。unique_ptrとshared_ptrを使った奇妙なsegfault

#include <memory> 
int main(int argc, char **arv) 
{ 
    int *i = new int; 
    std::unique_ptr<int> u1(i); 
    std::unique_ptr<int> u2; 
    u1 = std::move(u2); // line 7 
    std::shared_ptr<int> s1(i); // line 8 
    std::shared_ptr<int> s2; 
    s2 = s1; 
} 

私はG ++ 4.6と-std=c++0xでコンパイルするとセグメンテーション違反を取得します。

私が行7をu2 = std::move(u1);(バグだった)に変更した場合、それは消えます。 8行目をstd::shared_ptr<int> s1(new int(3));に変更した場合(当然のことではありません)、それも消えます。もし私が8行目から削除しても、セグメンテーションはありません。

だから害はありませんが、なぜセグメンテーションがあるべきかわかりません。私が理解する限り、
行7では、空のポインターがu1に割り当てられています。リセットなし()、スコープの終了はありません。それにもかかわらず、iは無効です。それは意図ですか?つまり、別のオブジェクトが破壊される可能性があるため、ポインタを移動するときには非常に注意する必要があります。

あなたはどう思いますか?私はどうやってこれから身を守るのですか?

おかげで、ステファン

答えて

11

あなたのライン8が間違っている:あなたはunique_ptriをキャプチャしたら、あなたは再びいくつか所有テイクオブジェクトにそれを与えることはありません!すべての所有者が*iを削除しようとしますが、これは間違っています。

std::shared_ptr<int> s1(std::move(u2)); 

は(また、あなたは間違った方法ラウンドu1u2を持っている。)

+1

私が気にするのは、 '-pedantic -Wall -Wextra'でコンパイルするときに警告を出さなくてもいいということです。答えは本当にちょうど "Do not!"ですか? – steffen

+2

@steffen:確かに、答えは「しない」です。 'int * p = new int;に対する保護はありません。 do_crazy_stuff(p); be_insane(p); take_ownership(p); 'コンパイラは、あなたがポインタを使って何をするのか本当に知ることができません。 –

+0

真実...デ・妄想のおかげで:) – steffen

3

このライン:

u1 = std::move(u2); 

u1によって保存された前回のポインタを削除することができるようになります。したがって、iポインタが解放されます。空ポインタを保持しているshared_ptrを作成すると、未定義の動作になります。

+0

ええ:

代わりに、あなたはユニークポインタから共有ポインタを作成する必要があります。私はそれを考え出した。 Kerrekへの私のコメントを見てください。何の警告もありません。コンパイラはここに自分自身を傷つける! – steffen

+0

ユニークなポインタを割り当てる方法は何も問題ありません。デフォルトで構築された一意のポインタはnullであり、割り当ては適切に古いリソースを破棄します。 'u1 = std :: move(u2);'行は '* i'を削除し、' u1'と 'u2'は両方ともnullです。 –

+0

@KerrekSB unique_ptrの割り当てに何か問題があったとは言いませんでした。 OPがそれをやっているところでは、 'u1'によって保持されているポインタは' u2'を移動割り当てした後freeです。問題は彼が(すでにfree'd)ポインタへのshared_ptrを作成することです。 Steffenは、コンパイラはshared/unique_ptrが何をポインタに格納するかを知る能力を持っていません。 – mfontanini

関連する問題