2017-12-12 6 views
2

std::vectorには、C++スマートポインタを使用してクラスを格納しています(Aとしましょう)(ベクトルの相違はstd::vector<std::shared_ptr<A>>です)。何らかの理由でshared_from_thisは、std :: shared_ptrの所有権の後でも空の_M_weak_thisです。

#include <iostream> 
#include <memory> 
#include <vector> 

class A : std::enable_shared_from_this<A> { 
public: 
    void doWork(); 
    std::shared_ptr<A> getSharedRef(); 
}; 

void A::doWork() { std::cout << "Working..." << std::endl; } 

std::shared_ptr<A> A::getSharedRef() { return shared_from_this(); } 

class AManager { 
    static std::vector<std::shared_ptr<A>> aList; 

public: 
    static void init(); // safety because statics 
    static void doLotsOfWork(); 
    static std::shared_ptr<A> createA(); 
}; 

std::vector<std::shared_ptr<A>> AManager::aList; 

void AManager::init() { aList = std::vector<std::shared_ptr<A>>{}; } 

void AManager::doLotsOfWork() { 
    for (auto a : aList) { 
    a->doWork(); 
    } 
} 

std::shared_ptr<A> AManager::createA() { 
    std::shared_ptr<A> a = std::make_shared<A>(); 

    aList.push_back(a); 
    return a->getSharedRef(); // <----- EXCEPTION 
} 

int main() { 
    AManager::init(); 
    AManager::createA(); 
    return 0; 
} 

、これはstd::bad_weak_ptrをスローし、検査時に、私はそのaに気づく、何らかの理由で、0x0、またはNULLに等しい_M_weak_thisを持っています。オブジェクトを参照している有効なstd::shared_ptrをすでに作成しているので、空であってはなりません。

さらに、A(変数付き)は完全にそのアドレスにそのまま残っているため、メモリの破損は起こっていません。

私は間違っていますか?

+6

あなたの説明はかなり良いです。エラーを正確に再現するコードを提供する方が良いでしょう。どのように[mcve]を作成するのかを見てください – AndyG

+0

この特定のケースでMCVEの最大の問題は、コードが多くの動く部品に依存しており、どの部品がエラーを引き起こしているのか正確にはわかりません。問題のコードにgithubリンクがありますが、それ以外の場合は、実際の例をスピンアップするのに数時間かかるでしょう。 – CalmBit

+1

なぜgetsharedref()が必要ですか? (そしてshared_from_this()を直接使用するのではないでしょうか?)Aは私的に継承するからですか?はいの場合、それは問題になる可能性があります。 –

答えて

3

問題は、あなたがenable_shared_from_this

shared_from_thisから個人的に継承しているためであると思わ「enable_shared_from_this<T>Tのアクセス可能基底クラスでなければならない。」が必要です([util.smartptr.enab]による)

個人的に継承することで、基本クラスにアクセスできなくなり、前提条件に違反します。私はこれが未定義の動作を意味すると推定します。 ClangとGCCの両方が例外をスローします。

解決方法は一般に継承されます。

class A : public std::enable_shared_from_this<A> { 
    //... 
}; 

* C++ 17で表現する[util.smartptr.shared.const]に移動しているように見えるが、要件は、基本的に同じです。

+0

これはコンパイル時に検出できないことは残念です。問題は 'std :: make_shared()'が 'enable_shared_from_this'から派生したクラスを' private'であると検出できなかったと考えているからです。refカウントはメンバの代わりに別のメモリブロックにあります。 'enable_shared_from_this'です。これは' shared_from_this() 'が間違っていると信じて投げるためです。 'enable_shared_from_this'はCRTPなので、STLライブラリは擬似公開検証メソッドを定義し、CRTPクラスを介して自己呼び出しを試みることができないため、プライバシーのためにコンパイルが失敗します。 – hadriel

+0

小修正:ref_countは 'make_shared'を使用しているのでいつもと同じ場所にありますが、' enabled_shared_from_this'の内部メンバー 'weak_ptr'はプライベートだったので設定されていません。 – hadriel

+0

"これはコンパイル時に検出できないことは残念です_"この非常に奇妙なハッキングツールには依存しないでください。あなた自身を初期化する 'weak_ptr'を持ってください。隠されていない、魔法のない、暗黙的なものはありません。 – curiousguy

関連する問題