1

スマート ポインター + 「これ」は有害と見なされるなどの関連する質問がありますか? しかし、彼らは私のケースを処理しません。これらの質問はすべて、スマート ポインターをカウントする参照の場合に生の this ポインターを公開することに関するものです。ただし、私の問題は、公開するthisのではなく、メソッドでのみ使用することですが、おそらく長期間使用することです。

次のコードを検討してください。

class X{
    void foo(){...} //Performs some long running task
}

shared_ptr<X> x;

void bar(){
    x->foo();
}

さて、いくつかのコードはfooオブジェクト x のメソッドを呼び出します。x の背後にあるインスタンスへの唯一のスマート参照は、1 つの shared_ptr x であると考えてください。ここで、foo は、他の関数などを呼び出す長時間実行されるタスクを実行します。

ここで、foo の実行中に、別のスレッド、シグナル ハンドラー、または での再帰呼び出しによってfoo、参照が変更またはクリアされるとしますx。これにより、オブジェクトの削除がトリガーされます。これでthis、コール スタック上のポインターはfoo、削除されたオブジェクトを指します。したがって、さらにコードを実行するfooと、予測できない結果が生じます。

これを回避する方法は?つまり、参照カウントによって処理されるオブジェクトのメソッドの実行中は常に、一部のコードがオブジェクトへの参照をクリアし、メソッド呼び出しが失敗したり、奇妙な結果を生成したりする危険性があります。問題はセマンティクスです。参照カウントは、オブジェクトへの参照がこれ以上ないと判断して削除しますが、これは正しくありませんthis。参照はまだありますが、悲しいことに、それはスマート ポインターではありません。

のようなものがあることは知っていenable_shared_from_thisますが、参照カウントされる可能性のあるオブジェクトのすべてのメソッドを常に書き直して、最初に共有ポインターを取得しthis、次にそのポインターを使用して、この問題を回避する必要がありますか? これによりすべてのメソッド コードが乱雑になり、さらに失敗する可能性もありxます。その後、物事は再び失敗します。

したがって、一般的な質問は次のとおりです。どのような種類のスマート ポインターを使用する場合でも、管理対象オブジェクトへのメソッド呼び出し中に安全を確保するにはどうすればよいでしょうか? thisメソッド内のポインターが無効にならないようにするにはどうすればよいですか? 最初のステートメントで使用するすべてのメソッドを書き直すことenable_shared_from_thisは良い解決策ですか?

それとも、参照がまだコール スタック上にあるときに参照をクリアするコードは、単純に形式が正しくないのでしょうか? しかし、そうであれば、複数のスレッドと複雑な再帰呼び出しが使用されると、形式が正しくないコードを記述するのは困難です...

4

2 に答える 2

1

複数のスレッドについて: スレッド間でデータを渡すときは、参照ではなく常にコピーで共有ポインターを渡す必要があります。このルールにより、別のスレッドが参照している共有ポインターをクリアしてもスレッドが失われないことが保証されます。

再帰的なメソッド呼び出しについて: はい、オブジェクトへの他の共有ポインターがクリアされる可能性がある共有ポインターを介してメソッドを呼び出すときは常に、共有ポインターのコピーをローカルに持つというルールにする必要があります。関数に共有ポインタを値で渡す場合、これは通常問題になりません。

私が見ることができる唯一のケースxは、クラス データ メンバーであるコードに表示されることです。

class C {
    shared_ptr<X> x;
public:
    void method1() { x.reset; }
    void method2() {
        x->foo();
    }
};

この場合、method1から呼び出すことができると考えられる場合X::fooは、 のローカル コピーを取得する必要がありますx。これは、共有ポインターをクラスに格納する場合にのみ問題となり、そのクラスのメソッドにのみ影響します。

于 2012-08-24T13:35:59.817 に答える
0

共有は思いやりです: 変数の新しい共有を取得してください!

shared_ptr<X> x;

void bar()
{
    shared_ptr<X> my_x = x;
    my_x->foo();
}
于 2012-08-24T08:20:23.723 に答える