2017-12-20 13 views
1

共有ポインタ、ラムダ、スコープに問題があります。共有ポインタが範囲外になった後にラムダに設定しました

私の状況は私が呼び出すメソッドがあるため、後で返される値を使用することができます。ここまでの正常な種類。問題は、このメソッドの中に非同期メソッドがあり、shared_pointerへの例外のセットを作成する必要があるときです。私はこの非同期メソッドからコールバックを処理するためにラムダ関数を使用しています。このラムダでは、私はshared_pointerを使用して、その例外(そのクラスのメソッド)をセットする必要があります。resultPtr-> setException();

私はshared_ptrを最初に使用し、次にラムダのweak_ptrを使用しました(なぜなら、shared_ptrがメモリリークを引き起こす可能性がある場所を読み込んでいるからです)。しかし、これまではshared_ptrを使う必要があります。

この例外が2番目の.cppに設定されているかどうかをテストする必要があるため、メソッドを呼び出して戻り値を使用します。私は約500ミリ秒待ってスレッドを入れて、それが例外を持っているかどうかをテストしますが、それはありません。しかし、非常にまれなケースでは、それは "hasException"です。私はラムダが呼び出されていることと、ログを通して例外を設定していることがわかりますが、最初に返された値は変更されないようです(別の場所を指しているようです)。

私が言及した最初の方法の入力は、私の場合は重要ではなく、単にポインタです。テストのために

file1.cpp 
typedef shared_ptr<Result> ResultPtr; 
ResultPtr method_name(TypePtr args) 
{ 
    if(args != nullptr) 
    { 
     ResultPtr result = make_shared<Result>(); 
     stuff->callAsync([this, result](input) 
     { 
      if(result == nullptr) 
      { 
       result->setException(); 
      } 
     }); 
    } 
    else 
    { 
     result->setError(); 
    } 
    return result; 
} 

file2.cpp 
bool testingMethod() 
{ 
    ResultPtr result = file1::methodName(TypePtr args) 
    std::this_thread::sleep_for(std::chrono::milliseconds(500)); 
    test(result->hasException); 
} 

は私が(ここでは重要ではない)特定の入力でこのメソッドを呼び出す別のクラスを使用していると私はresultPtrのオブジェクト値を比較する必要があります。私の場合は

は、私のようなものを持っています。何が起こるのは、スコープから外れるとすぐ(返り値)、私はもうオブジェクトにアクセスすることができないということです。私はこのメソッドを呼び出した後、スレッドを約1秒待機させますが、状態を変更することはありません(破棄されたオブジェクトを指すことはできません)。

これを克服する方法はありますか?その他の提案?

ありがとうございました!

+0

「stuff」とは何ですか? –

+1

"スコープから外れるとすぐ(返り値)、オブジェクトにアクセスできなくなります。これは真実ではないので、あなたがどのような問題を抱えているかは不明です。 [mcve] – Slava

+0

を提供するあなたの例は、多くの点で混乱しています。あなたの問題に関連するものに絞ってください。あなたは型なしでどこでも使用されている "args"を持っていますが、 "method_name"はメンバ関数ですが、型がない "input"クラスはありません.... https://stackoverflow.com/help/mcve Ifコンパイルできないという問題は、 "return a;"で、コンパイルされない行に絞ってください。 – lars

答えて

2

shared pointerが作成されたif(args)ブロックのスコープから外れると、destroyedになるので、もちろんオブジェクトにアクセスすることはできません。メソッドの外側にオブジェクトを置く必要があります。 g。これをクラスメンバーとして格納するか、グローバル変数に(<神秘>を禁止!)を格納します。

共有ポインタにラップする必要があるかどうかは不明ですが、what you want to achieveの明確な説明とともにMCVEを提供する必要があります。

1

callAsyncが本当に非同期の場合、ローカル変数resultaが範囲外であると、ラムダが実行を開始する可能性があります。必要な変数をパラメータとして渡す必要があります。 std::bindとの結合のように:

typedef shared_ptr<Result> ResultPtr; 
ResultPtr method_name(args) 
{ 
    if(args) 
    { 
     ResultPtr a = make_shared<Result>(); 
     std::weak_ptr<Result> result(a); 
     stuff->callAsync(std::bind([this](std::weak_ptr<Result> result_param) 
     { 
      auto resultPtr = result_param.lock(); 
      if(resultPtr) 
      { 
       resultPtr->setValue() 
       ...other stuff... 
      } 
     }, result)); 
    } 
    else 
    { 
     a->setError(); 
    } 
    return a; 
} 

とはい、あなたはそれが生きているオブジェクトを保持することを保証するために、ラムダが必要な場合は、あなたの例では、

+0

メソッドは非同期です。私はそれについての議論を提供するだけで、私が必要とするコールバックを後で受け取った(この非同期メソッドは私によって実装されておらず、変更もできない)。だから私はバインドがここではうまくいかないと思う。私の問題は、ラムダのshared_ptrの値を変更する必要があることですが、ラムダが実行される前に返されます。ラムダが実行して正しい値を設定しても、別のクラス(私はそれをテストしています)で返された値を使用しようとすると、2番目のクラスで使用しているポインタが更新されないようです。 –

1

を混乱されている理由あなたに渡すために弱いポインタを使用しているのではなく、共有ポインタ?ウィークポインタの目的は、オブジェクト自体を保持していない、見ている動作です。

ウィークポインタをキャプチャしているだけなので、ウィークポインタをロックする前に共有ポインタが有効範囲外になると共有ポインタが有効になりません。しかし、ウィークポインタを使用する代わりに共有ポインタをキャプチャするだけで(値によって、コピーが取られるように)することができます。その後、参照カウントがインクリメントされ、ラムダ内の共有ポインタはそれを生かし続けるでしょう、そして、両方の共有ポインタが範囲外になったときだけ削除されます。

このような共有所有権が共有ポインタの理由であるため、共有ポインタの参照カウントがゼロになった場合にオブジェクトにアクセスできなくなることが望ましい場合は、弱いポインタのみを使用する必要があります。

+0

はい私は今それを認識していますが、私が正しく考えているかどうかはわかりませんでした。元のコードはshared_pointersをlambdaに渡しました。あなたの答えの後、私は自分のソリューションにshared_ptrを保存することに決めました。しかし、それでも私の問題は解決しません。そのメソッドから返された値を使用しているとき、ラムダはコールバックを受け取ります。しかし、この値は私がテストのために使用しているこの他のメソッドで受け取った値を更新しません。 –

関連する問題