views:

201

answers:

2

I know the standard answer for a linker error about missing typeinfo usually also involves vtable and some virtual function that I forgot to actually define.

I'm fairly certain that's not the situation this time.

Here's the error:

UI.o: In function boost::shared_ptr<Graphics::Widgets::WidgetSet>::shared_ptr<Graphics::Resource::GroupByState>(boost::shared_ptr<Graphics::Resource::GroupByState> const&, boost::detail::dynamic_cast_tag)': UI.cpp:(.text._ZN5boost10shared_ptrIN8Graphics7Widgets9WidgetSetEEC1INS1_8Resource12GroupByStateEEERKNS0_IT_EENS_6detail16dynamic_cast_tagE[boost::shared_ptr<Graphics::Widgets::WidgetSet>::shared_ptr<Graphics::Resource::GroupByState>(boost::shared_ptr<Graphics::Resource::GroupByState> const&, boost::detail::dynamic_cast_tag)]+0x30): undefined reference totypeinfo for Graphics::Widgets::WidgetSet'

Running c++filt on the obnoxious mangled name shows that it actually is looking at .boost::shared_ptr::shared_ptr(boost::shared_ptr const&, boost::detail::dynamic_cast_tag)

The inheritance hierarchy looks something like

class AbstractGroup
{
   public:
      virtual ~AbstractGroup();
      typedef boost::shared_ptr<AbstractGroup> Ptr;
      ...
};

class WidgetSet : public AbstractGroup
{
    public:
       virtual ~WidgetSet();
       typedef boost::shared_ptr<WidgetSet> Ptr;
       ...
};

class GroupByState : public AbstractGroup
{
    public:
       virtual ~GroupByState();
       ...
};

Then there's this:

class UI : public GroupByState
{
    public:
       virtual ~UI();
       ...
       void LoadWidgets( GroupByState::Ptr resource );
       ...
};

Then the original implementation:

void UI::LoadWidgets( GroupByState::Ptr resource )
{
   WidgetSet::Ptr tmp( boost::dynamic_pointer_cast< WidgetSet >(resource) );
   if( tmp )
   {
       ...
   }
}

Stupid error on my part (trying to cast to a sibling class with a shared parent), even if the error is kind of cryptic.

Changing to this:

void UI::LoadWidgets( AbstractGroup::Ptr resource )
{
   WidgetSet::Ptr tmp( boost::dynamic_pointer_cast< WidgetSet >(resource) );
   if( tmp )
   {
       ...
   }
}

(which I'm fairly sure is what I actually meant to be doing) left me with a very similar error:

UI.o: In function boost::shared_ptr<Graphics::Widgets::WidgetSet>::shared_ptr<Graphics::_Drawer::Group>(boost::shared_ptr<Graphics::_Drawer::Group> const&, boost::detail::dynamic_cast_tag)': UI.cpp:(.text._ZN5boost10shared_ptrIN8Graphics7Widgets9WidgetSetEEC1INS1_7_Drawer5GroupEEERKNS0_IT_EENS_6detail16dynamic_cast_tagE[boost::shared_ptr<Graphics::Widgets::WidgetSet>::shared_ptr<Graphics::_Drawer::Group>(boost::shared_ptr<Graphics::_Drawer::Group> const&, boost::detail::dynamic_cast_tag)]+0x30): undefined reference totypeinfo for Graphics::Widgets::WidgetSet' collect2: ld returned 1 exit status

dynamic_cast_tag is just an empty struct in boost/shared_ptr.hpp. It's just a guess that boost might have anything at all to do with the error.

Passing in a WidgetSet::Ptr totally eliminates the need for a cast, and it builds fine (which is why I think there's more going on than the standard answer for this question).

Obviously, I'm trimming away a lot of details that might be important. My next step is to cut it down to the smallest example that fails to build, but I figured I'd try the lazy way out and take a stab on here first.

TIA!

EDIT: Show some more details that people have commented about

A: 

Are the members private? If so try adding protected: before the members of your classes.

class AbstractGroup
{
protected:
   typedef boost::shared_ptr<AbstractGroup> Ptr;
   ...
};


class WidgetSet : public AbstractGroup
{
protected:
    typedef boost::shared_ptr<WidgetSet> Ptr;
  ...
};

Another thing showed up after going back into your code sample. It looks like your trying to use polymorphism. The only problem is that you are dynamically casting the shared pointer object to a WidgetSet. After reading some documentation, I believe you should write resource.get_pointer() because you want to cast the pointer in the shared_ptr object and not the shared_ptr object itself. I am not really familiar with boost so please tell me if this makes any sense!

Alerty
Another detail I should have showed originally: all these pieces are public.Boost does some magic by adding dynamic_pointer_cast as a wrapper around the standard dynamic_cast. What you're describing seems to be a fairly common error, and probably the reason they worked that magic in the first place. If you do a get(), dynamic_cast it, and then assign it to another shared_ptr, it'll wind up getting deleted twice.
James
Very true! I was reading a bit too fast.
Alerty
+1  A: 

Without seeing your whole AbstractGroup class it's hard to be sure, but it sounds like you may not have any virtual functions in your class hierarchy. Try defining a virtual destructor in AbstractGroup (even an inline one will do) and see if that makes the difference. Without a single virtual function, there's no vtable and thus no place to hang the typeinfo data.

Drew Hall
Sorry, I should have shown that. There are definitely virtual members of each class.
James