hell_ical_vortex
hell_ical_vortex

Reputation: 359

Weak Pointer assignment failure

I am trying to have a shared_ptr to the parent node of a structure within itself. When deriving from such a data type, I want the parent pointer to be casted to the derived type.

Here is the piece of code I attempted to use.

#include <iostream>

#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/make_shared.hpp>
using boost::shared_ptr;
using boost::weak_ptr;
using boost::dynamic_pointer_cast;
using boost::make_shared;

struct A
{
  weak_ptr<A> parent;
  int i;
  virtual ~A() {}
};

struct B : virtual A
{
  int j;
  virtual ~B() {}
};

int main(int argc, char *argv[])
{
  B a, b;
  a.i = 1;
  a.j = 2;
  b.i = 4;
  b.j = 8;

  b.parent = weak_ptr<B>(make_shared<B>(a));
  //                     ^^^
  //                     The problem is here, not where I had 
  //                     thought it was earlier.

  shared_ptr<B> pb;
  if (pb = dynamic_pointer_cast<B>(b.parent.lock()))
  {
    // This is the code block that is intended to run
    // but the control does not flow here.
    std::cout << "b's parent: " << pb->i << ' '
        << pb->j << "\n";
  }
  else
  {
    std::cout << "Could not lock shared pointer or Pointer Null" << "\n";
  }

  return 0;
}

The output `fails' with the following message

Could not lock shared pointer or Pointer Null

Please explain the behaviour

Update:

  1. I changed the title, after I learnt from the explanations, that it was actually misleading.

  2. To me, The following comment from @Igor explain it best.

make_shared<B>(a) creates a temporary shared_ptr, which is destroyed at the semicolon. You assign it to weak_ptr - but weak_ptr alone doesn't keep the object alive

Upvotes: 1

Views: 1020

Answers (3)

Drax
Drax

Reputation: 13278

b.parent = weak_ptr<B>(make_shared<B>(a));

On this line you create a shared_ptr which dies on the same line.

The weak_ptr only stores a weak reference to it, so it doesn't count as a normal reference that increments the counter.

Therefore when you use the lock method of weak_ptr it returns an empty shared_ptr.

Upvotes: 4

CJCombrink
CJCombrink

Reputation: 3950

When you call the following:

b.parent = weak_ptr<B>(make_shared<B>(a));

The pointer gets destroyed as soon as the weak pointer is assigned, since the weak pointer will not try to keep the object alive.

Rememeber, if there are no more shared_ptr's to an object the pointer will destroy the object and the pointer will become invalid. This is the idea of smart pointers.

Also you are mixing pointer and non-pointer objects, this is bad and can cause issues: Take note, the call to make_shared<B>(a) will call the copy constructor of B to create a new instance of class B that is copied from a. So it is not really the parent of b, although you want it to be.

I suggest move completely over to smart pointers

int main()
{
    shared_ptr<B> a = make_shared<B>();
    shared_ptr<B> b = make_shared<B>();
    a->i = 1;
    a->j = 2;
    b->i = 4;
    b->j = 8;

    b->parent = a;

    shared_ptr<B> pb;
    if (pb = dynamic_pointer_cast<B>(b->parent.lock())) {}
}

Upvotes: 2

Revolver_Ocelot
Revolver_Ocelot

Reputation: 8785

b.parent = weak_ptr<B>(make_shared<B>(a));

This line creates temporary shared pointer to copy of a, and assigns weak pointer to it to b.parent

Then temporary shared pointer is destroyed, making b.parent point to destroyed pointer, so any attempt to .lock() it would fail.

Upvotes: 1

Related Questions