Jump to content
  • Advertisement
Sign in to follow this  
choffstein

std::vector and virtual functions [SOLVED]

This topic is 4843 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am trying to use std::vector, and for some reason it is saying that I am trying to call a pure virtual function. Here is an example of what I mean:
GeometryNode gnp;
//set gnp
...

//test
vector<SceneNodePtr> v;
v.push_back(gnp);
string sceneGraphString = v[0]->toString();
However, this does work:
GeometryNode gnp;
//set gnp
...

//test
string sceneGraphString = gnp->toString();
...well, at least until it hits the vectors within the toString() call. So we try something simpler...since SceneNode inherits Object, and GeometryNode inherits SceneNode, why don't we just try something really simple:
std::vector<VertexPtr> vertices;
VertexPtr v;
vertices.push_back(v);
string s = v[0]->toString();
CRASH! Now, I assume it isn't a bug with std::vector, but rather with my smart pointer class. But since calling toString() directly from the class seems to work, it must be with how they interact. So I have the base class called "Object" which has a method: virtual std::vector toString() = 0; All classes that inherit Object must overwrite this (for debugging reasons, and later, serialization reasons). Now, I am going to show my smart pointer code, but first I need to describe how it works. Firstly, it is NOT like a usual smart pointer. Well, it is and it isn't. It uses the inherited Object class to count references. However, it does NOT delete upon the reference count being 0, but rather returns it to the magical land of the Object Factory, which deletes it and adds the memory location back into the list of free locations for that class. I have extensively tested the ObjectFactory, so I highly doubt the error is in there. So here is my smart pointer code:
#ifndef __OBJECTFACTORYSMRTPTR_H__
#define __OBJECTFACTORYSMRTPTR_H__

#include "ObjectFactory.h"

namespace Symphony
{
	template <class U>
	class ObjectFactorySmartPtr
	{
		private:
			string className;
			U *ptr;
		
		public:
			
			//I dub thee: Dangerous
			ObjectFactorySmartPtr(U *p)
			{
				ptr = p;
				if(p)
					className = p->Type();
				else
					className = "DummyConversionClass";
			}
			
			ObjectFactorySmartPtr(string iClassName, bool create=true)
			{
				if(create)
					ptr = ObjectFactory::getInstance()->createInstance( iClassName.c_str(), ptr);
				className =iClassName;
			}
			
			ObjectFactorySmartPtr(const char *iClassName, bool create=true)
			{
				if(create)
					ptr = ObjectFactory::getInstance()->createInstance( iClassName, ptr );
				className = iClassName;
			}
			
			virtual ~ObjectFactorySmartPtr()
			{
				//LOG(mainLog, Logger::INFO, "Deconstructing smart pointer with " << ptr->GetReferences() << " references...");
				if(ptr)
				{ 
					ptr->Release();
					if(ptr->GetReferences() == 0) //other pointers could still be looking at it...
					{
						//LOG(mainLog, Logger::INFO, "Returning instance to the list...");
						ObjectFactory::getInstance()->freeInstance(className, ptr);
						ptr = NULL;
					}
				}
			}
			
			
			inline operator U*() const
			{
				if(NULL != ptr)
					return ptr;
				else
				{
					LOG(Logger::WARNING, "Calling getPtr() on ptr that does not exist!");
					return NULL;
				}
			}
			
			inline U& operator* () const
			{
				if(ptr)
					return *ptr;
				else
				{
					LOG(Logger::WARNING, "Calling operator*() on ptr that does not exist!");
					return NULL;
				}
			}
			
			inline U* operator-> () const
			{
				if(NULL != ptr)
					return ptr;
				else
				{
					LOG(Logger::WARNING, "Calling operator->() on ptr that does not exist!");
					return NULL;
				}
			}
			
			inline U* getPtr()
			{
				if(NULL != ptr)
					return ptr;
				else
				{
					LOG(Logger::WARNING, "Calling getPtr() on ptr that does not exist!");
					return NULL;
				}
			}
			
			inline ObjectFactorySmartPtr& operator= (U* pObj)
			{
				if(ptr)
				{
					ptr->Release();
					if(ptr->GetReferences() == 0)
					{
						//LOG(mainLog, Logger::INFO, "Returning instance to the list...");
						ObjectFactory::getInstance()->freeInstance(className, ptr);
						ptr = NULL;
					}
				}
					
				ptr = pObj;
				if(ptr)
					ptr->AddRef();
				
				return *this;
			}
			
			inline ObjectFactorySmartPtr& operator= (const ObjectFactorySmartPtr<U>& ref)
			{
				if(ptr)
				{
					ptr->Release();
					if(ptr->GetReferences() == 0)
					{
						//LOG(mainLog, Logger::INFO, "Returning instance to the list...");
						ObjectFactory::getInstance()->freeInstance(className, ptr);
						ptr = NULL;
					}
				}
				
				ptr = ref.ptr;
				if(ptr)
					ptr->AddRef();
				return *this;
			}
			
			inline bool operator== (U* pObj) const
			{
				return ptr == pObj;
			}
			
			inline bool operator!= (U* pObj) const
			{
				return ptr != pObj;
			}
			
			inline bool operator== (ObjectFactorySmartPtr<U>& ref) const
			{
				return ptr == ref.getPtr();
			}
			
			inline bool operator!= (ObjectFactorySmartPtr<U>& ref) const
			{
				return ptr != ref.getPtr();
			}
			
			//this is basically...witchcraft.  allows for "inherited" smart pointers
			template<class newType> // template function for 
			operator ObjectFactorySmartPtr<newType>() // implicit conversion ops. 
			{ 
				return ObjectFactorySmartPtr<newType>(ptr); 
			} 
	};
}

#endif


Anyone have any ideas why this could be breaking? Thanks! <3 visage [Edited by - visage on August 11, 2005 12:43:42 AM]

Share this post


Link to post
Share on other sites
Advertisement
Is GeomertyNode a typedef for an instantiation of your smart pointer class? How does it relate to SceneNodePtr?

Share this post


Link to post
Share on other sites
GeometryNode inherits SceneNode, which inherits Object. GeometryNodePtr is a typedef for ObjectFactorySmartPtr<GeometryNode>.

In other news, it turns out that this code:

vector<VertexPtr> v;
v.push_back(v2);
cout << v[0]->toString();



Does actually work, when v2 is type VertexPtr.

However, this does not:

vector<ObjectFactorySmartPtr<Object> > v;
v.push_back(v2);
cout << v[0]->toString();



It errors with a pure virtual method call.

This code:

vector<Object*> vec;
vec.push_back(v2.getPtr());
cout << vec[0]->toString();

Works like expected (v2.getPtr()) returns the smart pointer member pointer (which would be of type Vertex).

Ideas? Thanks.

Share this post


Link to post
Share on other sites
Ive been watching deconstruction times, and object IDs, et cetera, and I have stumbled across something wierd.
When I add the first element using push_back to a vector, things are fine.
The second element ends up calling the first ones deconstructor after push_back.
The third calls the first two deconstructors, which makes all my reference counts incorrect, despite the fact that the objects are still there.

list<> instead of vector<> maybe?

Share this post


Link to post
Share on other sites
For anyone who was wondering, yes, that was the issue -- coupled with the fact that I was doing SmartPtr sp = *it for iterators, which would create a reference, but not increase the reference count, which was making my objects destroy themselves early.

Share this post


Link to post
Share on other sites
I believe its calling the deconstructors after you do push-back because its resizing its array as you add more. The growth is almost exponential so it should eventually make plenty of space so it doesnt keep deconstructing the previous ones. You should be able to get around that by calling v.reserve(#) to enough space to hold a certain amount of elements.

Share this post


Link to post
Share on other sites
The actual problem seems to be that you never define a copy constructor. Remember the rule of three: if you define a copy constructor, assignment operator or destructor, then you probably need to define all three.

Share this post


Link to post
Share on other sites
Yep, SiCrane, you were right. I just realized it about 10 minutes ago -- just before I read this post infact.

Thanks for the help! Too bad I can't rate you any higher [smile]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!