std::vector and operator [] ?

Started by
14 comments, last by Trienco 17 years, 10 months ago
i am curious. what is the [] operator from the vector good for? i don't like the way for these sequence containers to loop through an array. i prefer a normal for( int i=0;i<Count;i++) blub.Draw(); but this doesn't work when i've defined blub std::vector<CBlub*> *blub but why? what do i need this vector for if not to use it to access the members of this element? do i really need to make it this way? std::vector<CBlub*>::iterator i; for(i = blub->begin(); i != blub->end(); i++) (*i)->Draw(); apart from that. i've got another question, what kind of speed impact do these containers have when i loop through them instead of just using a normal array CBlub *blub and loop then through every element? i'm asking because i've written a simple level loader, wich loads every object and to save these objects i use vectors. to perform the draw and movement etc.. for every object in my level, i would need to loop through these arrays several times per frame. how big is the impact on my frametime? i know i could just give the pointer from the sequence container to a standart array, but i would like to know if it is nessecary, regarding speed.
Advertisement
The [] operator works regardless of what the vector holds. In release builds the vector operator [] should compile to about the same speed as a raw array. If you need a fixed size array, then feel free to use a fixed size array. If you need the dynamic sizing of a vector, use the vector and you get essentially the same access speed as a raw array.
If you have a std::vector< CBlub * > * blub; then to iterate through it using operator[] you would need to do:
for (int i = 0; i < Count; ++i){	(*blub)->Draw();}
blub is a pointer to a vector, so you must dereference it before you can access it. Likewise, the vector that blub points to contains pointers, so you must dereference them before you can access them. The real question is why you're using a pointer to a vector of pointers, rather than just std::vector< CBlub > blub, which would allow your first example to compile as written.

As to the difference between a std::vector< CBlub > and a dynamically allocated CBlub *, in the worst case the overhead will be insignficant (the possible construction and destruction of a few additional CBlub objects) while in the best case std::vector will be far more efficient thanks to the separation of memory allocation and initialization. This is of course with full optimisations and provided that you use vector sensibly. There will be absolutely no difference in the time it takes to loop through a vector as opposed to a dynamically allocated array.

Σnigma
Out of my head: (*blub)->Draw();
EDIT: Wow, am I slow [smile]

Quote:Original post by SiS-Shadowman
i am curious. what is the [] operator from the vector good for?

It allows you to use the vector like you would an array, which means that your code that iterates using the index will work just fine.

Quote:but this doesn't work when i've defined blub std::vector<CBlub*> *blub but why? what do i need this vector for if not to use it to access the members of this element?


It doesn't work because you're using pointers everywhere. You'll need to dereference them like so:
for(int i=0 ; i<Count ; i++)    (*blub)->Draw();


Now, if you had just defined blub as std::vector<CBlub> blub then you could use your first block of code as is.

Quote:apart from that. i've got another question, what kind of speed impact do these containers have when i loop through them instead of just using a normal array CBlub *blub and loop then through every element?


When you do a release build (ie. optimisations are turned on), a std::vector should have exactly the same performance as an array when accessing elements. Inserting and removing will have a performance hit because of the dynamic memory allocation and re-shuffling of elements (unless you only insert or remove from the end of the vector), which is why you should make sure your using the right container. For example, if you were doing a lot of insertions/removes at random locations in a large dataset a std::list might be a better choice. For what your doing a vector sounds fine though.
"Voilà! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valorous visitation of a bygone vexation stands vivified, and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The only verdict is vengeance; a vendetta held as a votive, not in vain, for the value and veracity of such shall one day vindicate the vigilant and the virtuous. Verily, this vichyssoise of verbiage veers most verbose, so let me simply add that it's my very good honor to meet you and you may call me V.".....V
hm, i thanks for the quick answer.
i haven't worked much with these things yet. i only read some examples at http://cplus.about.com/od/stltutorial/l/aa110103a.htm about these sequence containers.

so basicly, what you say enigma, is that i shouldn't use any pointers with these vectors?

i think i don't fully understand how it works. just to show you how i use it.
std::vector<CMesh*> *Mesh;CMesh   *NewMesh;while(!EOF(pfile)) // i use tinyxml, but this would be the same for now...{     // read the file etc...     NewMesh = new Cmesh;     NewMesh->LoadMeshFile( some parameters from the file.. );     Mesh->insert(Mesh->end(), NewMesh);}


this is because i don't know how many objects i have to load out of the file.
but will it also work if i just have a CMesh NewMesh and insert it every time? i'm very unshure about it.
does the CMesh NewMesh now have to be in the array, so that everytime a new mesh gets created?

i'll try it out, but i need some assurance, the app works now and i don't want to screw it up ^^ i have done that too often.
I'm not saying you should never use pointers with vectors, I'm saying that if it makes sense to use a Class * array = new Class[dimension];, then it makes sense to use a std::vector< Class > array;.

I hope that example code isn't a direct copy from your project because it has undefined behaviour - you never actually allocate your vector. Assuming that just a error in your post the following would be equivalent (and potentially more efficient depending upon how heavyweight CMesh is):
std::vector< CMesh > Mesh;while(!EOF(pfile)) // i use tinyxml, but this would be the same for now...{	CMesh mesh;	mesh.LoadMeshFile(/*parameters*/);	Mesh.push_back(mesh);}
Of course, what would be even better would be if you were to rewrite CMesh so that initialization occurs in the constructor, in which case you could use:
std::vector< CMesh > Mesh;while(!EOF(pfile)) // i use tinyxml, but this would be the same for now...{	Mesh.push_back(CMesh(/*parameters*/));}
Σnigma
*thinking* now i see what your point is. ofcourse i'll allocate space for Mesh, it was just to show you what pointers i am using.

one last question ( i think ):

since we aren't dealing with pointers in your loop, the mesh objects gets copied one more time, isn't it? since it will be first initiated in the loop, then it is given as an argument to the vector, wich copies this element into it's own memory. won't that consume much time? i think about later, when i've several hundreds of objects in my scene and every one has not so less vertices ( wich results in big vertex/index buffers ) textures etc...

wouldn't it be better to just use
std::vector<CMesh*> Mesh;
and then just give the pointer to the allocated new mesh from the loop to Mesh?

my understanding of c++ doesn't go that far, it just sounds logical to me, but i've been wrong very often about that, so i just ask :)
Quote:Original post by SiS-Shadowman
wouldn't it be better to just use
std::vector<CMesh*> Mesh;
and then just give the pointer to the allocated new mesh from the loop to Mesh?


To tell you the truth, a good optimizing compiler (and the Microsoft one isn't too bad in that respect) will use some common optimization techniques to construct the Mesh object in place in the vector, so only one Mesh ever needs to be constructed and you don;t have to worry about pointers (and their attendant risks).

You would use the Mesh objects in the vector by using references to them.

The biggest problem would be that if the vector gets resized, them Mesh objects get copied. If there's a way to determine how many Mesh objects will ultimately be added to your vector, you can avoid that problem as well with the reserve() member function.

Using a vector of pointers will also eliminate deep vector copies and resizing of the vector is mush cheaper, but then you have to worry about explicit object lifetime control, invalid pointers, and the rest of the pointer snakepit.

Stephen M. Webb
Professional Free Software Developer

Quote:Original post by SiS-Shadowman
*thinking* now i see what your point is. ofcourse i'll allocate space for Mesh, it was just to show you what pointers i am using.

one last question ( i think ):

since we aren't dealing with pointers in your loop, the mesh objects gets copied one more time, isn't it? since it will be first initiated in the loop, then it is given as an argument to the vector, wich copies this element into it's own memory. won't that consume much time? i think about later, when i've several hundreds of objects in my scene and every one has not so less vertices ( wich results in big vertex/index buffers ) textures etc...

wouldn't it be better to just use
std::vector<CMesh*> Mesh;
and then just give the pointer to the allocated new mesh from the loop to Mesh?

my understanding of c++ doesn't go that far, it just sounds logical to me, but i've been wrong very often about that, so i just ask :)


You're correct for the wrong reasons.

Yes, if you had vector<Vertex> (as your vertex buffer) in your classes you'd spend ages copying that mesh into vector<CMesh>. However, your vertex buffers and index buffers and whatnot will generally be pointers to the data themselves, so they'll only occupy 4 bytes (whatever), which isn't much to copy. So you could store all your meshes in a vector<CMesh> without worrying, since at most they might have ~64 bytes, or more if you give your meshes names.

However: Since you're looking ahead to the future - you'd probably want your meshes to be stored in the vector as a pointer. This is because you may want many instances of the same mesh (for example, lots of the same tree) - so instead of giving each new model a new mesh with new vertices/indices, using lots and lots of memory, you could just give each model a pointer to just one mesh, and let them render that. Voila, memory saved!

You may want to look into boost::shared_ptr for that, though. If you feel it's beyond the scope of your abilities, don't worry - use regular pointers instead. You can always rewrite. Link to boost can be found in my signature.

Hope that helps.
[ search: google ][ programming: msdn | boost | opengl ][ languages: nihongo ]

This topic is closed to new replies.

Advertisement