[Boost-users] [SmartPtr] enable_shared_from_raw / weak_from_raw remains not associated

4 views
Skip to first unread message

Slava

unread,
May 16, 2013, 5:58:27 AM5/16/13
to boost...@lists.boost.org
I'm converting existing code with parent-child object tree to boost
shared_ptr/weak_ptr with parents having [now shared] ownership over the
children and children having weak reference to the parent. In the existing
code a parent usually becomes the children as constructor parameters, and
thus I have to extract the weak_ptr to "this" in constructor, which does
not work with current boost::enable_shared_from_this implementation. So I
am looking to enable_shared_from_raw alternative, which is promising, but
unfortunately does not quite work for my case. Here is a small example
demonstrating the issue:

test.cpp:

#include <boost/smart_ptr/enable_shared_from_raw.hpp>
#include <iostream>

struct Parent;

struct Child
{
Child()
{
std::cout << "Construct Child" << std::endl;
}
~Child()
{
std::cout << "Destruct Child" << std::endl;
}

boost::weak_ptr<Parent> parent;
};


struct Parent : public boost::enable_shared_from_raw
{
Parent(boost::shared_ptr<Child> _child)
{
std::cout << "Construct Parent" << std::endl;
this->child = _child;
this->child->parent = boost::weak_from_raw(this);
}

~Parent()
{
std::cout << "Destruct Parent" << std::endl;
}

boost::shared_ptr<Child> child;
};

int main()
{
boost::shared_ptr<Child> child(new Child());
boost::shared_ptr<Parent> parent(new Parent(child));
std::cout << "child->parent is " << (child->parent.lock() ? "not null"
: "null") << std::endl;
parent.reset();
std::cout << "child must be alone" << std::endl;
std::cout << "child->parent is " << (child->parent.lock() ? "not null"
: "null") << std::endl;
return 0;
}

`g++ -g -O0 test.cpp && valgrind a.out` produces:
==8467== Memcheck, a memory error detector
==8467== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==8467== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==8467== Command: a.out
==8467==
Construct Child
Construct Parent
child->parent is null
Destruct Parent
child must be alone
child->parent is null
Destruct Child
==8467==
==8467== HEAP SUMMARY:
==8467== in use at exit: 0 bytes in 0 blocks
==8467== total heap usage: 4 allocs, 4 frees, 112 bytes allocated
==8467==
==8467== All heap blocks were freed -- no leaks are possible
==8467==
==8467== For counts of detected and suppressed errors, rerun with: -v
==8467== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

The problem is that the weak_ptr to parent in child does not get
associated properly, when shared_ptr to parent is finally complete. Do I
expect too much from enable_shared_from_raw or did I hit some bug in the
implementation? I'm using boost 1.53.0-2 on Archlinux.

-- Slava

_______________________________________________
Boost-users mailing list
Boost...@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Frank Mori Hess

unread,
May 16, 2013, 2:09:58 PM5/16/13
to boost...@lists.boost.org
On Thu, May 16, 2013 at 5:58 AM, Slava
<Viatchesla...@h-d-gmbh.de> wrote:
> I'm converting existing code with parent-child object tree to boost
> shared_ptr/weak_ptr with parents having [now shared] ownership over the
> children and children having weak reference to the parent. In the existing
> code a parent usually becomes the children as constructor parameters, and
> thus I have to extract the weak_ptr to "this" in constructor, which does not
> work with current boost::enable_shared_from_this implementation. So I am
> looking to enable_shared_from_raw alternative, which is promising, but
> unfortunately does not quite work for my case. Here is a small example
> demonstrating the issue:


> struct Parent : public boost::enable_shared_from_raw
> {
> Parent(boost::shared_ptr<Child> _child)
> {
> std::cout << "Construct Parent" << std::endl;
> this->child = _child;
> this->child->parent = boost::weak_from_raw(this);
> }


weak_from_raw() doesn't work until after a shared_ptr has taken
ownership of the object or shared_from_raw() has been called. It's
been long enough don't remember what the rationale for this was, or if
there even was a rationale, but the enable_shared_from_raw test case
seems to expect this behavior. From looking at the code, it seems
like if you just called shared_from_raw prior to calling weak_from_raw
it would work.

Slava

unread,
May 17, 2013, 3:22:41 AM5/17/13
to boost...@lists.boost.org
On Thu, 16 May 2013 20:09:58 +0200, Frank Mori Hess <fmh...@gmail.com>
wrote:
Thanks, right, the test cases, I always forget they are the good source of
information!
The example works as expected (difference to previous is only addition of
boost::shared_from_raw(this) in constructor):

#include <boost/smart_ptr/enable_shared_from_raw.hpp>
#include <iostream>

struct Parent;

struct Child
{
Child()
{
std::cout << "Construct Child" << std::endl;
}
~Child()
{
std::cout << "Destruct Child" << std::endl;
}

boost::weak_ptr<Parent> parent;
};


struct Parent : public boost::enable_shared_from_raw
{
Parent(boost::shared_ptr<Child> _child)
{
std::cout << "Construct Parent" << std::endl;
this->child = _child;
boost::shared_from_raw(this); // necessary for weak_from_raw() to
function properly
this->child->parent = boost::weak_from_raw(this);
}

~Parent()
{
std::cout << "Destruct Parent" << std::endl;
}

boost::shared_ptr<Child> child;
};

int main()
{
boost::shared_ptr<Child> child(new Child());
boost::shared_ptr<Parent> parent(new Parent(child));
std::cout << "child->parent is " << (child->parent.lock() ? "not null"
: "null") << std::endl;
parent.reset();
std::cout << "child must be alone" << std::endl;
std::cout << "child->parent is " << (child->parent.lock() ? "not null"
: "null") << std::endl;
return 0;
}

output:
==2269== Memcheck, a memory error detector
==2269== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==2269== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==2269== Command: a.out
==2269==
Construct Child
Construct Parent
child->parent is not null
Destruct Parent
child must be alone
child->parent is null
Destruct Child
==2269==
==2269== HEAP SUMMARY:
==2269== in use at exit: 0 bytes in 0 blocks
==2269== total heap usage: 5 allocs, 5 frees, 152 bytes allocated
==2269==
==2269== All heap blocks were freed -- no leaks are possible
==2269==
==2269== For counts of detected and suppressed errors, rerun with: -v
==2269== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

I reached what I needed, but I have some bad feeling about how it works.
It does not look sane, boost::shared_from_raw(this) class is there only to
produce the desired side effect.

-- Slava

Frank Mori Hess

unread,
May 20, 2013, 11:02:06 AM5/20/13
to boost...@lists.boost.org
On Fri, May 17, 2013 at 3:22 AM, Slava
<Viatchesla...@h-d-gmbh.de> wrote:
> boost::shared_from_raw(this); // necessary for weak_from_raw() to
> function properly
> this->child->parent = boost::weak_from_raw(this);


> I reached what I needed, but I have some bad feeling about how it works. It
> does not look sane, boost::shared_from_raw(this) class is there only to
> produce the desired side effect.

You could just not use weak_from_raw at all. You can initialize your
weak_ptr from the shared_ptr returned by shared_from_raw.


--
Frank
Reply all
Reply to author
Forward
0 new messages