Jump to content
  • Advertisement
Sign in to follow this  
SiS-Shadowman

std::vector and operator [] ?

This topic is 4460 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 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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
*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 :)

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

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!