Discussion:
dynamic_cast of referenced objects
Kevin Wilder
2010-02-06 03:07:08 UTC
Permalink
Hi,

My project is throwing an occasional "unhandled win32 exception" error and I've been trying to figure out why. There is no consistency in the timing so I assume that I have a dangling pointer somewhere. (I don't have a memory leak because the memory usage shown in the Windows Task Manager is fairly constant while my code is running.)

I came upon a passage in the OpenSceneGraph Quick Start Guide that says:

"Be careful when returning the address of an object from a function. If you do this incorrectly, the ref_ptr<> storing the memory address could go out of scope before the address is placed on the return stack."

I assume that this also applies when passing referenced objects to a function... But most of the examples of callback functions that I have seen on the web all use standard C++ pointers in the function definition, rather than ref_ptr<>. For example:

--- snip ---

void operator()( osg::Node* node, osg::NodeVisitor * nv )
{
osg::MatrixTransform * MatrixXform = dynamic_cast<osg::MatrixTransform*>(node) ;

if ( MatrixXform )

--- snip ---

Thinking that this may be the source of my dangling pointer, I tried to modify my own callback function definition to use referenced object pointers per the quick start guide's recommendations. Unfortunately, I got hung up on the dynamic_cast in the code above. I can't figure out how to cast the osg::node referenced object pointer into an osg::MatrixTransform referenced object pointer.

Is there an equivalant means of casting an osg::ref_ptr<osg::node> into an osg::ref_ptr<osg::MatrixTransform> when using referenced object pointers? I'm trying to do something like:

--- snip ---

void operator()( osg::ref_ptr<osg::Node> node, osg::ref_ptr<osg::NodeVisitor> nv )
{
osg::ref_ptr<osg::MatrixTransform> MatrixXform = dynamic_cast<osg::ref_ptr<osg::MatrixTransform>(node) ;

if ( MatrixXform )

--- snip ---


Thanks for the help. I'm relatively new to OpenSceneGraph programming.

Cheers,

Kevin

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=23753#23753
Jean-Sébastien Guay
2010-02-06 03:32:01 UTC
Permalink
Hi Kevin,
Post by Kevin Wilder
My project is throwing an occasional "unhandled win32 exception" error and I've been trying to figure out why. There is no consistency in the timing so I assume that I have a dangling pointer somewhere.
I doubt you're on the right track with changing standard pointers to
ref_ptrs in function arguments, but when unsure it's better to use
ref_ptrs everywhere.

The "right way" to debug your error would be to compile a debug version
and run your code in a debugger. Then the debugger would likely tell you
exactly which pointer was left dangling, you'd have a stack trace, and
it would be relatively easy to track down the cause. Just sprinkling
ref_ptrs everywhere in the hope that it'll fix it is not a solution, IMHO.
Post by Kevin Wilder
--- snip ---
void operator()( osg::ref_ptr<osg::Node> node, osg::ref_ptr<osg::NodeVisitor> nv )
{
osg::ref_ptr<osg::MatrixTransform> MatrixXform = dynamic_cast<osg::ref_ptr<osg::MatrixTransform>(node) ;
if ( MatrixXform )
--- snip ---
osg::ref_ptr<osg::MatrixTransform> MatrixXform =
dynamic_cast<osg::MatrixTransform*>(node.get());

A ref_ptr is an object on the stack (not a pointer) that tracks a
pointer. And ref_ptr::get() returns a raw pointer to the underlying
object. So you can construct (or here, assign to) a ref_ptr from a raw
pointer.

So from right to left:
1. You extract the raw Node* pointer from a ref_ptr<Node>
2. You dynamic_cast that to a MatrixTransform*
3. You assign that to a ref_ptr<MatrixTransform>
4. Bob is your uncle.

Note that in the process, the ref count of node will be incremented if
it was really a MatrixTransform (i.e. if the assignment assigned
something other than NULL), so your function will have 2 refs (one in
the temporary ref_ptr<Node>, and one in the ref_ptr<MatrixTransform>).
This is unnecessary, as the temporary ref_ptr<Node> in the function
arguments guarantees that the object will not be deleted in the scope of
the function. So you could do this instead:

osg::MatrixTransform* MatrixXform =
dynamic_cast<osg::MatrixTransform*>(node.get());

As I said, storing it in a raw pointer is safe at that point because of
the temporary ref_ptr<Node> in the function arguments which will be
destroyed when the function ends.

So you see, ref_ptrs require a bit of work wrapping your mind around
them, but it's not magic and it all works really well.

Hope this helps,

J-S
--
______________________________________________________
Jean-Sebastien Guay jean-sebastien.guay-***@public.gmane.org
http://www.cm-labs.com/
http://whitestar02.webhop.org/
Tim Moore
2010-02-06 16:37:35 UTC
Permalink
Post by Kevin Wilder
Hi,
...
"Be careful when returning the address of an object from a function. If you
do this incorrectly, the ref_ptr<> storing the memory address could go out
of scope before the address is placed on the return stack."
osg::Node* func()
{
osg::ref_ptr<Node> result;
...
return result.get(); // result gets deleted!
}

Instead of returning "result.get()" you need to return "result.release()"
which prevents the ref_ptr destructor from deleting the object. As a side
node, I think this idiom is unfortunate; ref_ptrs should be returned by
loading and scene graph creation functions that run in the database pager
thread. Live objects with a ref count of 0 are a bad thing.
Post by Kevin Wilder
I assume that this also applies when passing referenced objects to a
function... But most of the examples of callback functions that I have seen
on the web all use standard C++ pointers in the function definition, rather
--- snip ---
void operator()( osg::Node* node, osg::NodeVisitor * nv )
{
osg::MatrixTransform * MatrixXform =
dynamic_cast<osg::MatrixTransform*>(node) ;
if ( MatrixXform )
This style of code is common in OSG. It is safe because the caller has a
ref_ptr somewhere that points to the node.
Post by Kevin Wilder
--- snip ---
Thinking that this may be the source of my dangling pointer, I tried to
modify my own callback function definition to use referenced object pointers
per the quick start guide's recommendations. Unfortunately, I got hung up on
the dynamic_cast in the code above. I can't figure out how to cast the
osg::node referenced object pointer into an osg::MatrixTransform referenced
object pointer.
Is there an equivalant means of casting an osg::ref_ptr<osg::node> into an
osg::ref_ptr<osg::MatrixTransform> when using referenced object pointers?
--- snip ---
void operator()( osg::ref_ptr<osg::Node> node,
osg::ref_ptr<osg::NodeVisitor> nv )
{
osg::ref_ptr<osg::MatrixTransform> MatrixXform =
dynamic_cast<osg::ref_ptr<osg::MatrixTransform>(node) ;
if ( MatrixXform )
--- snip ---
If you still want to do that, you can say
osg::ref_ptr<osg::MatrixTransform> MatrixXform =
dynamic_cast<osg::MatrixTransform*>(node.get());
Post by Kevin Wilder
Thanks for the help. I'm relatively new to OpenSceneGraph programming.
Cheers,
Kevin
Tim
Paul Martz
2010-02-06 17:39:26 UTC
Permalink
Post by Kevin Wilder
"Be careful when returning the address of an object from a function.
If you do this incorrectly, the ref_ptr<> storing the memory address
could go out of scope before the address is placed on the return stack."
osg::Node* func()
{
osg::ref_ptr<Node> result;
...
return result.get(); // result gets deleted!
}
Instead of returning "result.get()" you need to return
"result.release()" which prevents the ref_ptr destructor from deleting
the object.
Yes, "result.release()" is the correct way to return a Referenced
address stored in a local ref_ptr<> without causing the memory to be
deleted.

The current edition of the Quick Start Guide (QSG) doesn't use release()
and instead advises returning a ref_ptr<> instead of a regular C
pointer. This works but is somewhat inefficient because it creates a
ref_ptr<> that typically would exist for no more that a few
instructions. release() is better, and the QSG example code has been
updated to use release(), but the actual QSG itself still needs rewriting.
-Paul
Kevin Wilder
2010-02-08 17:44:12 UTC
Permalink
Hi,

Thank you both for all of your help!

Cheers,

Kevin

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=23805#23805
Trond Vidar Stensby
2010-02-08 18:20:31 UTC
Permalink
Post by Kevin Wilder
My project is throwing an occasional "unhandled win32 exception" error and I've been trying to figure out why.
One thing you should check is if you have any raw C++ pointers pointing to objects that are also pointed to by ref_ptr's. Accessing the object through the raw pointer after that the ref_ptr's have gone out of scope is illegal since the object is automaticly destroyed when the last ref_ptr goes out of scope.

Notice that since OSG uses ref_ptr's in most places any object that you add to a scenegraph will most likely be referenced by a ref_ptr. You should therefore try to avoid using raw pointers to such objects. It's safer to use ref_ptr's.

Example: the following will fail


Code:
osg::Node* myTransform = new osg::MatrixTransform();
{
osg::ref_ptr< osg::Group > myGroup = new osg::Group();
myGroup->addChild(myTransform);
}
myTransform->someMethod(); // Wrong. Object has been deleted.




In the example above replace the first line with:

Code:
osg::ref_ptr< osg::Node > myTransform = new osg::MatrixTransform();


and use myTransform.get() inside the addChild call.

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=23809#23809
Kevin Wilder
2010-02-09 23:57:28 UTC
Permalink
Hi,

For anyone who is still following this thread (or for anyone who stumbles upon it while trying to solve a similar problem in the future), I figured I'd post my findings:

The bit about the object reference pointers vs. standard C++ pointers turned out to be a red herring. Seems the crashes resulted from my method of updating 2D text in the scene. I was just calling "->settext("blah")" from the main loop whenever I wanted to change the displayed characters. The crashes went away when I implemented a callback function to update the text. Here's an example of my text update callback function:


Code:


struct TextUpdateCallback : public osg::Drawable::UpdateCallback
{
virtual void update(osg::NodeVisitor* nv, osg::Drawable* drawable)
{
osgText::Text * TextPointer = dynamic_cast<osgText::Text*>(drawable) ;

if ( TextPointer )
{
TextPointer->setText(NewText) ;
TextPointer->setColor(NewColour) ;
}
}
}





I hope this helps.

Cheers,

Kevin[/quote]

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=23879#23879
Tueller, Shayne R Civ USAF AFMC 519 SMXS/MXDEC
2010-02-10 00:19:29 UTC
Permalink
Kevin,

Thanks for sharing. I'm sure it will come in handy...:)

Regards,
-Shayne

-----Original Message-----
From: osg-users-bounces-***@public.gmane.org
[mailto:osg-users-bounces-***@public.gmane.org] On Behalf Of Kevin
Wilder
Sent: Tuesday, February 09, 2010 4:57 PM
To: osg-users-***@public.gmane.org
Subject: Re: [osg-users] dynamic_cast of referenced objects

Hi,

For anyone who is still following this thread (or for anyone who stumbles
upon it while trying to solve a similar problem in the future), I figured
I'd post my findings:

The bit about the object reference pointers vs. standard C++ pointers turned
out to be a red herring. Seems the crashes resulted from my method of
updating 2D text in the scene. I was just calling "->settext("blah")" from
the main loop whenever I wanted to change the displayed characters. The
crashes went away when I implemented a callback function to update the text.
Here's an example of my text update callback function:


Code:


struct TextUpdateCallback : public osg::Drawable::UpdateCallback
{
virtual void update(osg::NodeVisitor* nv, osg::Drawable* drawable)
{
osgText::Text * TextPointer = dynamic_cast<osgText::Text*>(drawable) ;

if ( TextPointer )
{
TextPointer->setText(NewText) ;
TextPointer->setColor(NewColour) ;
}
}
}





I hope this helps.

Cheers,

Kevin[/quote]

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=23879#23879
Robert Osfield
2010-02-10 09:30:10 UTC
Permalink
Hi Keven,

It sounds it you were modifying the text on each frame without setting
the DataVariance to DYNAMIC, and you were running the viewer
multithreaded so the draw dispatch ended overlapping with the update
of the text.

Robert.
Post by Kevin Wilder
Hi,
struct TextUpdateCallback : public osg::Drawable::UpdateCallback
{
 virtual void update(osg::NodeVisitor* nv, osg::Drawable* drawable)
 {
   osgText::Text * TextPointer = dynamic_cast<osgText::Text*>(drawable) ;
   if ( TextPointer )
   {
     TextPointer->setText(NewText) ;
     TextPointer->setColor(NewColour) ;
   }
 }
}
I hope this helps.
Cheers,
Kevin[/quote]
------------------
http://forum.openscenegraph.org/viewtopic.php?p=23879#23879
_______________________________________________
osg-users mailing list
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
Continue reading on narkive:
Loading...