Search code examples
c++shared-ptrweak-ptr

enable shared from this crash


I am trying to create a grid with every point pointing to another from the grid (member variable drain_), possibly itself. I wanted to use shared_ptr for this and so I would need to use a weak_ptr for drain since it can point to itself.

Problem is, this code crashes in the shared_ptr_base.h file:

// Now that __weak_count is defined we can define this constructor:
  template<_Lock_policy _Lp>
    inline
    __shared_count<_Lp>::__shared_count(const __weak_count<_Lp>& __r)
    : _M_pi(__r._M_pi) <------ HERE <-------
    {
      if (_M_pi != nullptr)
    _M_pi->_M_add_ref_lock();
      else
    __throw_bad_weak_ptr();
    }

With the stack:

std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count at shared_ptr_base.h:824 0x418898
std::__shared_ptr::__shared_ptr at shared_ptr_base.h:949 0x418873
std::shared_ptr::shared_ptr() at shared_ptr.h:251 0x418845
std::enable_shared_from_this::shared_from_this() at shared_ptr.h:573 0x41881b
Node::drainInitialization() at point.cpp:43 0x417f3e
Grid::initialize() at openlem.cpp:799 0x407677
Grid::Grid() at openlem.hpp:152 0x4175dd
main() at orogen.cpp:24 0x417361

Do you have any idea what I am doing wrong? Here is my code:

int main(){
    int  m = 12, n = 13;
    Grid grid = Grid ( m, n );
}

grid.hpp:

class Grid
{
private:
    std::vector<std::vector<NodePtr> > lattice_;    // lattice of nodes
}

grid.cpp:

void Grid::initialize ( int m, int n ){
    this->m_ = m;
    this->n = n;
    lattice_.reserve( m );
    for ( int i = 0; i < m; ++i ){
        lattice_.push_back( std::vector<NodePtr>() );
        lattice_[i].reserve( n );
        for ( int j = 0; j < n; ++j ){
//          NodePtr test = std::make_shared<Node>( );
            NodePtr test = std::shared_ptr<Node>( new Node );
            lattice_[i].push_back( std::move( test ) );
            test->drainInitialization();

            printf( "%i %i \n", lattice_.size(), lattice_[0].size() );
            printf( "%i %i \n", i, j );
        }
    }
}

node.hpp:

class Node : public std::enable_shared_from_this<Node>
{
    typedef std::shared_ptr<Node> NodePtr;
public:
    Node (); // Constructor
    void drainInitialization();
    ~Node (); // Destructor

    int          i; // Coordinate
    int          j; // Coordinate
    std::weak_ptr<Node> drain_;   // flow target
}

node.cpp:

Node::Node(): i(init_int), j(init_int), elevation_(init_double),
chann_el_slope_(init_double), chann_wa_slope_(init_double),
water_level_(init_double), uplift_(init_float), discharge_(init_uint),
border_(0), marker_(0){}

void Node::drainInitialization(){
    drain_ = shared_from_this();
}

Solution

  • After lattice_[i].push_back( std::move( test ) ), test is no longer valid and is a null pointer. There is no need to move shared_ptr, just copy it into the vector.

    Alternatively you can still move into the vector but then use lattice_[i].back()->drainInitialization() rather than test->drainInitialization().