Skip to main content
GameDev.net gamedev.net
🔒 Locked

Deriving from std::vector

Started by floatingwoods Jul 16, 2008 at 7:33 PM 13 replies 1.6k views
Original Post
floatingwoods
floatingwoods
Hi, I'd like to derive template std::vector so that I get an int-value instead of a size_type-value when calling the .size() member function. What I have looks like following and it is declared in the stdafx.h. The problem is that I now get error messages as follows: error C2661: 'CMyVector::CMyVector' : no overloaded function takes 2 arguments or error C2664: 'CMyVector::CMyVector(const CMyVector &)' : cannot convert parameter 1 from 'int' to 'const CMyVector &' What is wong?

template <class T> class CMyVector :public std::vector<T>
{
	public: 
	int size() const
	{
		return (int(std::vector<T>::size()));
	}
};
#define stdVector CMyVector

jpetrie
jpetrie
size_type is an int (it's just going to be unsigned). This is a horrible reason to derive from vector -- what do you feel you need this for?
fpsgamer
fpsgamer
Well your pursuit sounds dubious.

First of all containers are not designed to be inherited. The biggest reason why is the fact they do not have virtual destructors.

Additionally I have no idea why size_type is not sufficient for you? What difference would it make to you what type it is as long as its integral (which it is)?
Antheus
Antheus
This would be the absolutely worst possible reason to do something like that.

Show the calling code that causes the original problem. It's an indication of something being very wrong there - not in the vector.
gfxnomad
gfxnomad
I agree with the rest of the posters that this is a horrible reason to derive from std::vector. However, the fact that std::vector.size returns an unsigned integral type often does cause the annoying warning "warning: comparison between signed and unsigned integer expressions". Also, explicitly casting all over the place to get rid of this is really annoying. I try to use size_t wherever I don't absolutely need signedness to minimize this annoyance.
floatingwoods
floatingwoods
Well, I just wanted to quickly try to get rid of all my warnings linked to following type of expression (however I hardly know what a template is.. ):

for (int i=0;i...

Which gives me following warning:

warning C4018: '<' : signed/unsigned mismatch

I could disable this type of warning, but I then warnings for more useful cases would also be disabled... or I could replace about 1000 occurences of above-type loop with:

for (int i=0;i...

or

for (unsigned int i=0;i...

(the latter case would require me to look more carefully at the code I change)
Oxyd
Oxyd
Just do int size(std::vector const& v) { return static_cast(v.size()); } ?

And yeah, I think you're doing something wrong elsewhere.

EDIT: Okay, seeing your code -- what exactly do you think is wrong with the last loop? If you loop in the interval <0; v.size()), you obviously don't need a signed integer -- its value never will be negative, no matter if you use unsigned or signed int. What exactly do you think you would have to be careful about?
Driv3MeFar
Driv3MeFar
Edit: I should read posts more carefully. Making the loop counter unsigned is more correct, but TBH I do a mix of both.
jpetrie
jpetrie
The latter case (making the loop iteration type unsigned) is the correct solution.
floatingwoods
floatingwoods
Thanks for all your input, I know I am a horrible c/c++ programmer ;)
Antheus
Antheus
Quote:
Original post by floatingwoods
Well, I just wanted to quickly try to get rid of all my warnings linked to following type of expression (however I hardly know what a template is.. ):

for (int i=0;i...

Which gives me following warning:

warning C4018: '<' : signed/unsigned mismatch


This is solved through typedefs in a generic way.

The reason for size_type being defined in such a way is because it may change. Perfectly generic way to write such loop would be:
typedef std::vector<int> MyIntVector; // whichever type you have...MyIntVector::size_type i;for (i = 0; i < aVector.size(); ++i) ;
Or, depending on what the loop does:
MyIntVector::iterator i;for (i = aVector.begin(); i != aVector.end(); ++i)

chairthrower
chairthrower
using an unsigned int as an indexer loses 4 bytes of precision on 64 bit (g++/unixy thing).

int main(){       std::cout << "sizeof unsigned                 " <<   sizeof( unsigned) << std::endl;    std::cout << "sizeof size_t                   " <<   sizeof( size_t) << std::endl;    std::cout << "sizeof vector< char>::size_type " <<   sizeof( std::vector< char>::size_type) << std::endl;}


yields ...
sizeof unsigned 4
sizeof size_t 8
sizeof vector< char>::size_type 8
Bregma
Bregma
Quote:
Original post by fpsgamer
First of all containers are not designed to be inherited. The biggest reason why is the fact they do not have virtual destructors.

That's simply incorrect.

Standard containers are designed not to be used polymorphically. That's why they do not have virtual destructors.

They are designed to be inherited. That's a sensible way to use them. In fact, I would argue it's the preferred way to use them in order to take advantage of the strong typing offered by C++. A typedef just doesn't do enough. Either a typedef or inheritance should be used to introduce a name for a new type instead of using the container explicitly all through the code.
class ids: public std::vector<int>{ }class scores: public std::vector<int>{ }// If a typedef were used for the above, this function could be called with "ids".void show_scores(const scores& s){  // ...}
Quote:
Additionally I have no idea why size_type is not sufficient for you? What difference would it make to you what type it is as long as its integral (which it is)?
This is the crux. The OP is trying to solve the wrong problem (changing the type returned by a function when it's the type he assigns the value to that's incorrect).

The proper solution would be this.
class score_list: public std::vector<int>{ }int main(int, char*[]){    score_list scores;    // ...populate scores...    // indexing    for (score_list::size_type i = 0; i < scores.size(); ++i)    {      show_scores(scores);    }    // alternative: iterating    for (score_list::const_iterator it = scores.begin; it != scores.end(); ++it)    {      show_scores(*it);    }}

Stephen M. Webb
Professional Free Software Developer
Nyarlath
Nyarlath
Quote:
Original post by floatingwoods
What is wong?

The problem is that your only way to construct a CMyVector is using the default autogenerated constructors (empty and copy).

You need to write a constructor for each one of the vector (at least every one you want to use), i.e...

// empty constructorCMyVector(): vector() { }	// copy constructorCMyVector(const CMyVector& other): vector(other.begin(), other.end()) { }// default valuesexplicit CMyVector(size_type _Count) : vector(_Count) { }CMyVector(size_type _Count, const _Ty& _Val) : vector(_Count, _Val) { }// ... provide access to alloc and iterator constructors ...
RobTheBloke
RobTheBloke
Quote:
Original post by Bregma
They are designed to be inherited. That's a sensible way to use them. In fact, I would argue it's the preferred way to use them in order to take advantage of the strong typing offered by C++.


hmmm. a debatable point of view. I agree that for the most part deriving classes from std::vector and other containers works, and is actually quite a nice way to use them (in some cases). But, it's not a blanket solution that should be promoted as a pattern for all situations. A simple case where it causes problems is:

#define EXPORT __declespec(dllexport)class EXPORT MyArray : std::vector<Foo> {};


And in DLL case scenarios, this may cause some problems as well since you may be using different STL implementations on different compilers...

class EXPORT MyArray{public:private:  std::vector<Foo> mInternal;};


At which point it's probably a nice idea to use pimpl techniques to hide the actual implementation completely....

class EXPORT MyArray{public:  MyArray();  ~MyArray();private:  void* mInternal;};MyArray::MyArray() {  mInternal = new std::vector<Foo>;}MyArray::~MyArray() {  std::vector<Foo>* ptr = (std::vector<Foo>*)mInternal;  delete ptr;}

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.