3

Somehow after p->start() is called - shared_from_this throws bad_weak_ptr.
But as you can see p->start() called after shared_ptr is fully initiated.

struct A : std::enable_shared_from_this<A> 
{
    std::thread* t = nullptr;
    A() {}
    ~A(){ 
        t->join(); 
        delete t; 
    }
    void f() { 
        try{
            auto p = this->shared_from_this(); 
            std::cout << "p:" << p.get() << "\n";
        } catch(...) { 
            std::cout << "Exception !!!\n"; 
        }
    }
    void start() { 
        t = new std::thread(&A::f,this); 
    }
};
std::shared_ptr<A> create() { 
    A* a = new A();
    std::shared_ptr<A> p(a);
    p->start();
    return p;
}
int main()
{   
    int i = 0;
    std::map<int,std::shared_ptr<A>> map;
    while( i < 1024) { 
        auto ptr = create();
        map[i++] = ptr;
    } 
    return 0;
}

link to working code (coliru) - unexplained bad_weak_ptr - exception is thrown ...

zx485
  • 28,498
  • 28
  • 50
  • 59
Roma
  • 39
  • 5
  • 1
    You need to `join` all the threads before `main` returns. – o11c Feb 14 '17 at 22:02
  • 1
    I am joining each thread in A's dtor. A's dtor will be called when map's dtor is called -> before main returns. In any case seems like it still does not explain bad_weak_ptr. – Roma Feb 14 '17 at 22:07
  • Why are you dynamically allocating a `std::thread`? A `std::thread` is a move-only handle to a thread, you can just default-construct it and then move-assign a new value to it. Don't use `new`/`delete` for `std::thread` objects. – Jonathan Wakely Feb 14 '17 at 22:25
  • 1
    If you did `std::thread(&A::f, shared_from_this());` then the new thread would share ownership, and the destructor wouldn't run before the thread has finished. – Jonathan Wakely Feb 14 '17 at 22:29
  • thnx for explanation – Roma Feb 14 '17 at 22:34

1 Answers1

5

Your problem is that you have a race condition on the join. main may be exiting, destroying your objects in the map. The shared_ptr in the map is destroyed, calling your object's destructor which wants to join, but it's too late: the shared_ptr that enable_shared_from_this wants to use is toast. Then (race condition) in the object's own thread it tries to get a shared from this on a dead weak_ptr, which causes the exception to be thrown and message printed on cout.

Mark B
  • 95,107
  • 10
  • 109
  • 188