Jump to content
  • Advertisement
Sign in to follow this  
Syreth

pushing abstract class pointers onto a vector

This topic is 4874 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

Since, when STL vectors (as well as other containers) push_back() an object they do it by making a copy using the object's copy constructor, how do you push a pointer to a derived class into an STL container like vector (from within a different scope especially) when you can't define a true virtual copy constructor? Most of the time it's said to use the "clone" method as a simulation for a "virtual copy constructor" but that seems only useful if you're explicitly calling it. If you did the following:
//Assume Base is abstract and Derived has a virtual inherited clone() implemented
//Assume BaseVector is external to the scope of the function and is defined as

vector<Base *> BaseVector;

void function(int x, int y)
{
  Derived * temp = new Derived(x, y);

  //This won't work because temp only exists in the function
  BaseVector.push_back(temp);  

  //It this valid and/or good practice? 
  BaseVector.push_back(temp->clone()); 

  delete temp;
}

Assuming that the vector is properly deallocated later, is the second call to push_back() there valid? What exactly happens there? It seems that push_back() will make a copy somehow of the *new* object that is a cloned copy of temp. So temp can die once the function is over and the vector, which is outside the scope, will have a pointer to a separate piece of memory that is identical and "permanent". But if push_back() assumes the use of a copy constructor and there isn't a real one defined then what happens? What's a good way to do this?

Share this post


Link to post
Share on other sites
Advertisement
Pushing a pointer to an object of a derived class on to a STL container, is standard practice.

STL containers DO create a copy of the thing you're pushing on, but if that is a pointer, THEY ONLY COPY THE POINTER.

This is very important to note - the object will *NOT* be copied, only the pointer (which is fine, as it's just a pointer).

You should also note, that if you delete the object after you've pushed the pointer into your STL container, the container will now contain a dangling pointer - which is bad and will result in program failure.

So it should be:


//Assume Base is abstract but don't need Derived to have a virtual inherited clone() implemented
//Assume BaseVector is external to the scope of the function and is defined as

vector<Base *> BaseVector;

void function(int x, int y)
{
Derived * temp = new Derived(x, y);

// No need to clone anything at this point.

//This will work because it only copies the pointer, not the object
BaseVector.push_back(temp);

// Note that we must NOT delete temp, because it is still in the vector - only delete
// it when it's been removed from the vector.
}



Mark

Share this post


Link to post
Share on other sites
It should be valid. The vector only stores the pointer, not the object itself.

PS: Your clone has to be something like this:

Derived* clone() const
{
return new Derived(*this);
}

Share this post


Link to post
Share on other sites
As most of your Qs have already been answered, i'll just say that the standard library containers manage there own memory via the allocator types (typically the last template type parameter which has a defeault std::allocator), any dynamic allocation of memory you do yourself it is responsibility to give it back when done.

So i suggest you look into smart pointers and store those in standard library containers instead this will not only take of memory at the wright time it can help the problem of object-ownership. The C++ boost library has a package of smart pointers you can use.

Also if contiguousness elements in memory is not important you should prefer using std::deque, it is also random accessible. With this is in mind i would do:


#include <boost/shared_ptr.hpp>
#include <boost/pool/pool_alloc.hpp>
#include <deque>

typedef boost::shared_ptr<base> base_ptr;
typedef std::deque< base_ptr, boost::fast_pool_allocator<base_ptr> > base_con;


Quote:
Original post by Koen
PS: Your clone has to be something like this:

Derived* clone() const
{
return new Derived(*this);
}


@Syreth if your not understanding that he is probably referring to covariant return types:


struct base {

virtual base* clone() const = 0;
virtual ~base() {}
};

struct derived : base {

derived* clone() const { return new derived; }
};

Share this post


Link to post
Share on other sites
I wasn't entirely sure about the "only the pointer is copied" concept. Thank you very much for ellucidating that. I feel clean now.

As for smart pointers and such, I've read multiple places that there are some issues with using those with some of the STL containers so I have opted to manually clean up in my class destructors.

And as a further note/question about the clone(), I've implemented my clone() successfully but only when I declare/define them as such:


//in Base
virtual Base * Clone() const = 0;

//in Derived
virtual Base * Clone() const;




When I declare the derived as returning the pointer to the class I get thhis compilation error:

'Derived::Clone' : overriding virtual function differs from 'Base::Clone' only by return type or calling convention

and a host of other related errors. It only works when I declare the derived Clone() functions as Base pointer return types and let it upcast. My compiler complains the exact same way when I use snk_kid's example too.

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!