Click to See Complete Forum and Search --> : override vector::insert


paradoxresolved
April 15th, 2008, 06:34 AM
Can someone please show me how to override vector::insert?

I've tried:
template <class T> iterator MyVector::insert ( iterator it, const T& x )
{
vector<T>::insert(it,x);
// my code here
}

However, it tells me that I need more parameters for iterator, but I'm not sure what.

MyVector is derived from vector.

Thank you.

GNiewerth
April 15th, 2008, 07:07 AM
STL containers are not intended to be derived from because they donīt have a virtual destructor. Use composition instead to reuse std::vector. Your class needs to wrap its own methods around vectorīs methods.


template<typename T>
class myvector
{
std::vector<T> Impl_;

public:
// typedef iterator type
typedef typename std::vector<T>::iterator iterator;
typedef typename std::vector<T>::const_iterator const_iterator;


iterator insert( iterator it, const T& op )
{
return Impl_.insert( Impl_.begin(), op );
}
}


Please note that most methods of vector come in pairs to ensure const correctness.

paradoxresolved
April 15th, 2008, 08:48 AM
Thanks! I'll give it a shot.

paradoxresolved
April 16th, 2008, 06:31 AM
Rats. I'm going to have to recreate the interface for .at(..), .push_back(..), .pop_back(), .size(), as well as .insert(..), and perhaps a few others that I'm not readily thinking of. . .

.at(..) returns const_reference, which apparently isn't the same thing as T&.

Is the NO way to force the destructor for vector, so that I can keep my vector class as derived?? What if I .clear() the vector during the derived destructor?

Paul McKenzie
April 16th, 2008, 06:40 AM
Rats. I'm going to have to recreate the interface for .at(..), .push_back(..), .pop_back(), .size(), as well as .insert(..), and perhaps a few others that I'm not readily thinking of. . .

.at(..) returns const_reference, which apparently isn't the same thing as T&.What exactly are you trying to accomplish by deriving from std::vector?
Is the NO way to force the destructor for vector,What do you mean by "force the destructor"? so that I can keep my vector class as derived??Since you derived from vector, when your object is destroyed, vector is destroyed. There is no such thing as destroying a parent and having the derived remain intact.

Regards,

Paul McKenzie

souldog
April 16th, 2008, 06:53 AM
for example. Really not much to do


#include <vector>

template<typename T>
class VectorHolder
{
public:
virtual ~VectorHolder(){}

void clear() {TVector_.clear();}
bool empty() const {return TVector_.empty();}
std::vector<T>::size_type size() const {return TVector_.size();}
std::vector<T>::const_iterator begin() const {return TVector_.begin();}
std::vector<T>::iterator begin() {return TVector_.begin();}
std::vector<T>::const_iterator end() const {return TVector_.end();}
std::vector<T>::iterator end() {return TVector_.end();}

std::vector<T>::const_reference operator[](const std::vector<T>::size_type i) const {return TVector_[i];}
std::vector<T>::reference operator[](const std::vector<T>::size_type i) {return TVector_[i];}
std::vector<T>::const_reference at(const std::vector<T>::size_type i) const {return TVector_.at(i);}
std::vector<T>::reference at(const std::vector<T>::size_type i) {return TVector_.at(i);}

protected:
std::vector<T> TVector_;
};

Philip Nicoletti
April 16th, 2008, 07:12 AM
1.

.at(..) returns const_reference, which apparently isn't the same thing as T&.


???? there are two signatures for at()... one return a reference and
one returns a const reference

2. What exactly are you trying to accomplish in overriding insert() ?
The normal way is composition.

3. I think that you could use PRIVATE inheritance ... but you
would need to provide implementations for the functions that
you want.

paradoxresolved
April 16th, 2008, 04:38 PM
Ok, I have tried this:


vector<T>::reference at(uint index);

template<typename T> vector<T>::reference MyVector<T>::at(uint index)
{
return this_vector.at(index);
}


It then returns the error:
error C2662: 'at' : cannot convert 'this' pointer from 'const class MyVector<class boost::shared_ptr<class MyObject> >' to 'class MyVector<class boost::shared_ptr<class MyObject> > &'

I see that there are two versions of .at(..). Is it confusing the one I want??

Why do I want to derive a class from vector? It simplifies my code considerably. Long story. Making it a member of another class works just as well, I suppose. I just can't get the interface to play nicely now. :(

MrDoomMaster
April 16th, 2008, 05:13 PM
template< typename t_type >
class MyVector : public std::vector<t_type>
{
public:
~MyVector()
{
std::vector<t_type>::~vector();
}

iterator insert( iterator it, const t_type& x )
{
std::vector<t_type>::insert(it,x);
// my code here
}
};

:) *dodges all of the sharp weapons being thrown at him*

Paul McKenzie
April 16th, 2008, 05:18 PM
Why do I want to derive a class from vector? It simplifies my code considerably.How does it simplify your code? Show me an example of where code is simplified by deriving from vector. Deriving because it saves typing is not justification for derivation.

There is something in your derived class that wasn't provided by vector, else you wouldn't have derived from it. Whatever those things are, you could more than likely have implemented them using algorithm or some other functions that worked on vector, or iterators in general.

Regards,

Paul McKenzie

Paul McKenzie
April 16th, 2008, 05:21 PM
template< typename t_type >
class MyVector : public std::vector<t_type>
{
public:
~MyVector()
{
std::vector<t_type>::~vector();
}

This code is ill-formed. The "natural" destruction process will already destroy the parent, and then you're calling it again, causing undefined behaviour.



Regards,

Paul McKenzie

MrDoomMaster
April 16th, 2008, 05:33 PM
Oh, yeah! Good catch. I had a brain fart.

paradoxresolved
April 16th, 2008, 06:12 PM
I'm wrapping a class around vector such that, when this class is a member of a parent class, it automatically stores a pointer to the parent in the child object that is "pushed back" in the vector. It forms a tree that can search down to the root.

Otherwise, I have to go through all my code and set the parent at each and every instance of "push_back." It's highly time-consuming, messy, and error-prone.

paradoxresolved
April 16th, 2008, 06:31 PM
I'm still getting the error with the ".at(..)" interface. MSDN says there are two .at(..) functions in vector


reference at(size_type pos);
const_reference at(size_type pos) const;




It seems the second of the two is firing off, when the first is what I need.

My .at(..) function is:


vector<T>::reference at(uint i)
{
return TVector_.at(i);
}


Do I need to define both versions?

laserlight
April 16th, 2008, 10:07 PM
It seems the second of the two is firing off, when the first is what I need.
That will only happen if the current object is const in the given context.

Do I need to define both versions?
Yes.

Paul McKenzie
April 17th, 2008, 02:36 AM
I'm wrapping a class around vector such that, when this class is a member of a parent class, it automatically stores a pointer to the parent in the child object that is "pushed back" in the vector.So it sounds like you are just saving typing, and there is no IS-A relationship as to why you publically derived from vector.
Rats. I'm going to have to recreate the interface for .at(..), .push_back(..), .pop_back(), .size(), as well as .insert(..), and perhaps a few others that I'm not readily thinking of. . .This is an indication that the interface wasn't fully thought through. I would expect, as a user of this tree class, functions such as AddNode(), RemoveNode(), GetNodeCount(), etc. and these functions would in turn call the internal vector's push_back(), pop_back(), size() etc. functions. The vector is hidden from the user, and the underlying data structure used to maintain the tree is not exposed. If in the future the vector needs to be changed to another data structure that has no "push_back" method, for example, then the clients using the tree class need not have to change their code. With your design, any client using the tree now needs to changed if in the future a "better" underlying structure is used.
I have to go through all my code and set the parent at each and every instance of "push_back." It's highly time-consuming, messy, and error-prone.I don't quite understand what you're saying. Maybe show a real life code example of what you are doing and where it is messy and time consuming.

Regards,

Paul McKenzie

paradoxresolved
April 17th, 2008, 09:09 AM
Laserlight: Thank you, that was the case. I finally figured it out after two hours of head-to-wall trauma, copious cursing, and plenty of rum-n-coke.

Paul: I don't intend for anyone to ever use this code but me. When it is all finished, it will be wrapped up by an external interface.

Saving typing is one way to help make code less error prone. Why else would you tuck reduntant code into a function? Instead of setting a pointer to the parent at each time you push_back or insert something into a vector, the idea was to create a wrapper class that does it automatically, whenever something is push_back into its internally stored vector. I never have to worry about whether or not I remember to set the pointer. Now, it's impossible not to. If the object being stored is not of the appropriate type, it won't even store the object. I wanted the interface to the wrapper class to be similar enough to the way vectors work because I'm familiar with that interface. Actually, for my purposes, there are very few vector functions that I use on a typical basis, and since I no one else will be using these classes, I only needed to define a handful for the wrapper class interface.

That, and I never liked the way erase worked. Why don't they have vector<T>::erase(uint index)???? It seems more straightforward to me.

Philip Nicoletti
April 17th, 2008, 09:29 AM
That, and I never liked the way erase worked. Why don't they have vector<T>::erase(uint index)???? It seems more straightforward to me.


Just a guess : Probably to keep it consistent with other containers,
and, given the index, it is easy to come up with the iterator:


v.erase( v.begin()+index );



Actually, for my purposes, there are very few vector functions that I use on a typical basis, and since I no one else will be using these classes, I only needed to define a handful for the wrapper class interface.


More and more it seems like containment (or private inheritance)
is the way to go.

std::stack (and the others like it), internally use a vector or list,
but only have a few vector/list member functions that they actually
allow client code to use.

Paul McKenzie
April 17th, 2008, 10:10 AM
Paul: I don't intend for anyone to ever use this code but me.However, when we're asked a question that goes against all common C++ knowledge, be prepared to get more questions asked of why you're doing things this way.
Saving typing is one way to help make code less error prone.If you get a C++ interview question as to why public derivation is done, please don't say "to save typing". Public derivation is done to model the is-a relationship between a parent and base object. Yes, the by-product of public inheritance is that you do not need to implement code in the base class, but in no means is saving keystrokes the main reason for deciding to derive publicly from a class.
Why else would you tuck reduntant code into a function?Deciding whether to derive from a class is not the same principle as coming up with a generic function. If it were, 'C' programmers and other non-OO people would have no trouble with OO programs, as all a class would be is syntactic sugar for procedural calls (which of course, it isn't).
I wanted the interface to the wrapper class to be similar enough to the way vectors work because I'm familiar with that interface.So exactly what was wrong with Gniewerth's code? It is a "vector" class, in that it contains a vector and has routines that call the internal vector's functions.
That, and I never liked the way erase worked. Why don't they have vector<T>::erase(uint index)???? It seems more straightforward to me.Because STL uses the iterator concept for most of their functions and algorithms. If you need to erase an element after a find() is done, the iterator from find() can be used directly.

Regards,

Paul McKenzie

paradoxresolved
April 17th, 2008, 10:51 AM
Actually, I did switch to his suggestion after his post. I was no longer deriving from vector, but was tucking it away as a member instead. That's what I meant before. Sorry. There must have been a miscommunication. I was just trying to carry over the functions from vector that I use the most into the interface of the enclosing class, but was having trouble getting them to work. I got it fixed last night. All is well.

Interviewing? Nah. This is my hobby. If it were my job, I would have to work on other people's projects, and it wouldn't be fun anymore. :)

Thanks for everyone's help!