Allegro.cc - Online Community

Allegro.cc Forums » Game Design & Concepts » std::vector, Where Have You Been All My Life?

This thread is locked; no one can reply to it. rss feed Print
 1   2 
std::vector, Where Have You Been All My Life?
Charles256
Member #8,370
February 2007

I remember learning about vectors in my beginning c++ programming class. Long time ago,but they are awsome. Been developing in PHP for five years and I must admit, that was awsome too. I love them both. :-D

Jakub Wasilewski
Member #3,653
June 2003
avatar

Quote:

std::copy(mystrlist.begin(), mystrlist.end(), ostream_iterator<string>(cout, "item seperator"));

Oh my God. I think I'd prefer to write it out as a for loop. You know, so that my eyes don't bleed :-).

---------------------------
[ ChristmasHack! | My games ] :::: One CSS to style them all, One Javascript to script them, / One HTML to bring them all and in the browser bind them / In the Land of Fantasy where Standards mean something.

ImLeftFooted
Member #3,935
October 2003
avatar

Quote:

You know, so that my eyes don't bleed :-).

Yes but its fukcing blazing fast. That statement will be faster then writing out the for loop yourself!

For the kind of efficiency, thats the cleanest code I've ever seen.

C++ was meant to be fast and elegant, not noobish. Don't mistake the two.

CGamesPlay
Member #2,559
July 2002
avatar

Quote:

That statement will be faster then writing out the for loop yourself!

Err... prove it.

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

Carrus85
Member #2,633
August 2002
avatar

Oh, and lets not forget the opposite operation:

vector<string> tokens;
copy(istream_iterator<string>(cin), istream_iterator<string>(), back_inserter(tokens));

;D

ImLeftFooted
Member #3,935
October 2003
avatar

CGamesPlay said:

Err... prove it.

A compiler can unroll the loop, as well as a plethora of other tricks.

Jakub Wasilewski
Member #3,653
June 2003
avatar

Quote:

A compiler can unroll the loop.

Really? The compiler has no prior knowledge of the number of elements in mystrlist, so it can't unroll it fully. It can partially unroll it (i.e., execute it in blocks of 8 iterations or whatever using the Duff's device for example), but that can be just as easily done to any for loop.

I'm not saying it won't be faster - maybe it will be. But it's still butt ugly, and I'm not convinced it actually does provide a benefit. Anyway, the point is moot in that case, because the majority of the time will be spent on output to cout.

---------------------------
[ ChristmasHack! | My games ] :::: One CSS to style them all, One Javascript to script them, / One HTML to bring them all and in the browser bind them / In the Land of Fantasy where Standards mean something.

HoHo
Member #4,534
April 2004
avatar

Quote:

Err... prove it.

1#include <iostream>
2#include <vector>
3#include <algorithm>
4#include <ctime>
5 
6using namespace std;
7 
8const int SIZE=10000000;
9const int LOOPS=100;
10int main(){
11 vector<int> intvec1(SIZE);
12 vector<int> intvec2(SIZE);
13 //warmup
14 copy(intvec1.begin(), intvec1.end(), intvec2.begin());
15 cout<<"Total time to copy "<<SIZE<<" ints from one vector to other "<<LOOPS<<" times:"<<endl;
16 clock_t before=clock();
17 for(int i=0;i<LOOPS;i++){
18 copy(intvec1.begin(), intvec1.end(), intvec2.begin());
19 }
20 clock_t after=clock();
21 cout<<"std::copy: "<<(after-before)<<endl;
22 
23 before=clock();
24 for(int i=0;i<LOOPS;i++){
25 for(int j=0;j<SIZE;j++){
26 intvec2[j]=intvec1[j];
27 }
28 }
29 after=clock();
30 cout<<"regular loop: "<<(after-before)<<endl;
31 return 0;
32
33}

One sample output wit g++ -O2:Total time to copy 10000000 ints from one vector to other 100 times:
std::copy: 2620000
regular loop: 2870000
</code>Without optimizations:

Total time to copy 10000000 ints from one vector to other 100 times:
std::copy:    2830000
regular loop: 30390000

Satisfied?
:P

Using cout would have been pointless as its overhead would have been way too high for measuring the actual looping process

[edit]
With vectors that fit into cache:
No optimizations:

Total time to copy 100000 ints from one vector to other 10000 times:
std::copy:    320000
regular loop: 29170000

-O2

Total time to copy 100000 ints from one vector to other 10000 times:
std::copy:    350000
regular loop: 490000

__________
In theory, there is no difference between theory and practice. But, in practice, there is - Jan L.A. van de Snepscheut
MMORPG's...Many Men Online Role Playing Girls - Radagar
"Is Java REALLY slower? Does STL really bloat your exes? Find out with your friendly host, HoHo, and his benchmarking machine!" - Jakub Wasilewski

CGamesPlay
Member #2,559
July 2002
avatar

Use iterators :P

1#include <iostream>
2#include <vector>
3#include <algorithm>
4#include <ctime>
5 
6using namespace std;
7 
8const int SIZE=100000;
9const int LOOPS=10000;
10int main(){
11 vector<int> intvec1(SIZE);
12 vector<int> intvec2(SIZE);
13 //warmup
14 copy(intvec1.begin(), intvec1.end(), intvec2.begin());
15 cout<<"Total time to copy "<<SIZE<<" ints from one vector to other "<<LOOPS<<" times:"<<endl;
16 clock_t before=clock();
17 for(int i=0;i<LOOPS;i++){
18 copy(intvec1.begin(), intvec1.end(), intvec2.begin());
19 }
20 clock_t after=clock();
21 cout<<"std::copy: "<<(after-before)<<endl;
22 
23 before=clock();
24 for(int i=0;i<LOOPS;i++){
25 for(int j=0;j<SIZE;j++){
26 intvec2[j]=intvec1[j];
27 }
28 }
29 after=clock();
30 cout<<"regular loop: "<<(after-before)<<endl;
31 
32 before=clock();
33 for(int i=0;i<LOOPS;i++){
34 vector<int>::const_iterator j = intvec1.begin();
35 vector<int>::iterator k = intvec2.begin();
36 while(j != intvec1.end())
37 {
38 *k++ = *j++;
39 }
40 }
41 after=clock();
42 cout<<"iterator loop: "<<(after-before)<<endl;
43 return 0;
44
45}

cgames@ryan ~ $ g++ test.cpp -O3 -funroll-loops
cgames@ryan ~ $ ./a.out 
Total time to copy 100000 ints from one vector to other 10000 times:
std::copy:     690000
regular loop:  970000
iterator loop: 900000

Okay, so it's faster, and by a fair margin, but why?

[edit]
While loop is faster :)

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

Jakub Wasilewski
Member #3,653
June 2003
avatar

Here is the loop I had in mind:

for(int i=0;i<LOOPS;i++)
  for(it1 = intvec1.begin(), it2 = intvec3.begin(); it1 != intvec1.end(); it1++, it2++)
    (*it2) = (*it1);

With regular loop changed to that, and -O2:

Quote:

Total time to copy 10000000 ints from one vector to other 1000 times:
std::copy: 34062
regular loop: 34641

Negligible 1.5% difference.

Anyway, I was just playing - if there is a good way to use <algorithm> by all means, you should use it.

But it's not all that important if the loop version will be more readable. This is not so in the case of std::copy, which is very straight-forward. But in the case of algorithms that require you to define a function (which will often be used only this once), it's not worth the hassle. Not unless we get lambda functions in C++.

---------------------------
[ ChristmasHack! | My games ] :::: One CSS to style them all, One Javascript to script them, / One HTML to bring them all and in the browser bind them / In the Land of Fantasy where Standards mean something.

CGamesPlay
Member #2,559
July 2002
avatar

Here's a silly.

1#define _str(foo) #foo
2#define str(foo) _str(foo)
3#define TYPE list
4 
5#include <iostream>
6#include <list>
7#include <algorithm>
8#include <ctime>
9 
10using namespace std;
11 
12const int SIZE=10000;
13const int LOOPS=100000;
14int main(){
15 TYPE<int> intvec1(SIZE);
16 TYPE<int> intvec2(SIZE);
17 //warmup
18 copy(intvec1.begin(), intvec1.end(), intvec2.begin());
19 cout<<"Total time to copy "<<SIZE<<" ints from one " str(TYPE) " to other "<<LOOPS<<" times:"<<endl;
20 clock_t before=clock();
21 for(int i=0;i<LOOPS;i++){
22 copy(intvec1.begin(), intvec1.end(), intvec2.begin());
23 }
24 clock_t after=clock();
25 cout<<"std::copy: "<<(after-before)<<endl;
26 
27 before=clock();
28 for(int i=0;i<LOOPS;i++){
29 TYPE<int>::const_iterator j = intvec1.begin();
30 TYPE<int>::iterator k = intvec2.begin();
31 while(j != intvec1.end())
32 {
33 *k++ = *j++;
34 }
35 }
36 after=clock();
37 cout<<"iterator loop: "<<(after-before)<<endl;
38 return 0;
39
40}

$ g++ test.cpp -O3 -funroll-loops && power ./a.out 
Total time to copy 10000 ints from one list to other 100000 times:
std::copy:     7220000
iterator loop: 6930000

<hypothesis>It seems copy is doing a memcpy internally, overridden for vectors. When it can't do so and must use a generic copy function, the overhead of the method pointers causes it to be slower.</hypothesis>

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

HoHo
Member #4,534
April 2004
avatar

Put all together and ran on my Core2 at 32bit:

#g++ std_copy.cpp -O3 -funroll-loops && ./a.out

Total time to copy 100000 ints from one vector to other 10000 times:
std::copy:     390000
regular loop:  550000
iterator loop: 580000
Jakub's loop:  560000

I ran it several times and there weren't much changes.

Different CPU's might give different results.

__________
In theory, there is no difference between theory and practice. But, in practice, there is - Jan L.A. van de Snepscheut
MMORPG's...Many Men Online Role Playing Girls - Radagar
"Is Java REALLY slower? Does STL really bloat your exes? Find out with your friendly host, HoHo, and his benchmarking machine!" - Jakub Wasilewski

CGamesPlay
Member #2,559
July 2002
avatar

You have a fast machine, HoHo :) What clock/cache?

I'm running a Core Duo at 3.0 GHz with I think 4 MB cache between the cores.

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

HoHo
Member #4,534
April 2004
avatar

Core2Duo e4300@2.93GHz at the moment. That means 2M L2 shared between two cores and ~62% OC. Could go higher when I could somehow give it more than default voltage :)
Your last code with -O3 -funroll-loops gave me this:

Total time to copy 10000 ints from one list to other 100000 times:
std::copy:     1480000
iterator loop: 1520000

When I changed list to vector then iterator loop actually got faster than std::copy :o

Total time to copy 10000 ints from one vector to other 100000 times:
std::copy:     480000
iterator loop: 430000

Well, all I can say is when in doubt, benchmark :)
Also please note the speed difference between lists and vectors.

__________
In theory, there is no difference between theory and practice. But, in practice, there is - Jan L.A. van de Snepscheut
MMORPG's...Many Men Online Role Playing Girls - Radagar
"Is Java REALLY slower? Does STL really bloat your exes? Find out with your friendly host, HoHo, and his benchmarking machine!" - Jakub Wasilewski

ImLeftFooted
Member #3,935
October 2003
avatar

Yeah lists are bloated and are almost completely useless because of it. They're more useful for academic purposes then anything else.

anonymous
Member #8025
November 2006

Quote:

Yeah lists are bloated and are almost completely useless because of it. They're more useful for academic purposes then anything else.

Hm, lists have faster insertions that vectors. You can remove elements in constant time. If you sort a list of MyClass (using list::sort), it could seriously outperform std::sort on vector, because it doesn't need to copy actual data, just rearrange the pointers.
However, iterating through a list is slower, because vector uses a random_iterator.

Each STL container has its strenghts and weaknesses. Sometimes it might even be more efficient to use one type for one task, and then copy the data to a different container to do something else with the data.

For example, std::set is blazing fast to get you unique, sorted data. If you needed a lot of random access on the data later, you might copy it to a vector before continuing. (Benchmark, of course.)

***

By the way, they say that the container's "native" methods could be faster than the equivalent std::algorithm (optimized for this particular container). Anybody care to benchmark operator = ?

HoHo
Member #4,534
April 2004
avatar

Quote:

Hm, lists have faster insertions that vectors You can remove elements in constant time

If the vector doesn't need to be sorted you can add and remove stuff from there in constant time too.

Quote:

If you sort a list of MyClass (using list::sort), it could seriously outperform std::sort on vector, because it doesn't need to copy actual data

That depends on how you use it. If you have enormous list then iterating it over and over again will probably take more time than with vectors (need benchmarks!). If you don't keep pointers in the container and the elements are big then lists may win.

Quote:

Each STL container has its strenghts and weaknesses

I agree. Though if you can alter your design just a little you may find that vectors perform better than lists for most things. Also in some cases deque may be a bit better than vector.

Last time I used lists was about three years ago in uni when we were asked to write a list class :)

__________
In theory, there is no difference between theory and practice. But, in practice, there is - Jan L.A. van de Snepscheut
MMORPG's...Many Men Online Role Playing Girls - Radagar
"Is Java REALLY slower? Does STL really bloat your exes? Find out with your friendly host, HoHo, and his benchmarking machine!" - Jakub Wasilewski

anonymous
Member #8025
November 2006

Quote:

If the vector doesn't need to be sorted you can add and remove stuff from there in constant time too.

That's a big "if". And a vector may get copied using push_back(). And if you wanted to keep the container sorted, a multiset would probably be fastest.

Quote:

Quote:

If you sort a list of MyClass (using list::sort), it could seriously outperform std::sort on vector, because it doesn't need to copy actual data

That depends on how you use it. If you have enormous list then iterating it over and over again will probably take more time than with vectors (need benchmarks!). If you don't keep pointers in the container and the elements are big then lists may win.

List can win clearly, if the copy constructor is expensive. For example when sorting std::strings.

Quote:

Quote:

Each STL container has its strenghts and weaknesses

I agree. Though if you can alter your design just a little you may find that vectors perform better than lists for most things. Also in some cases deque may be a bit better than vector.

Last time I used lists was about three years ago in uni when we were asked to write a list class :)

Yes, a vector is a most general use container, because very often random access is what you need (replacement to single array). However, it is impossible to design a container that works remarkably well for all purposes, because you need a different structure for each purpose. Knowing the tools is good, also STL is designed in a way, that it is relatively easy to switch the container you are using and to move data to a different container.

I can also see how implementing your own list deters you from using std::list :)

Carrus85
Member #2,633
August 2002
avatar

Quote:

Quote:

If the vector doesn't need to be sorted you can add and remove stuff from there in constant time too.

That's a big "if". And a vector may get copied using push_back(). And if you wanted to keep the container sorted, a multiset would probably be fastest.

Not if it is a compliant STL implementation and you have already reserved enough slots for your data set (two conditions which are easily satisfied).

Quote:

Quote:

Quote:

If you sort a list of MyClass (using list::sort), it could seriously outperform std::sort on vector, because it doesn't need to copy actual data

That depends on how you use it. If you have enormous list then iterating it over and over again will probably take more time than with vectors (need benchmarks!). If you don't keep pointers in the container and the elements are big then lists may win.

List can win clearly, if the copy constructor is expensive. For example when sorting std::strings.

Of course, vectors can easily win if you don't sort the actual array contents (you generate an sorted index->actual index mapping that happens to return items in sorted order). Completely avoids copy constructor overhead. Granted, this is not what is done in any STL container as far as I know, but it is possible to sort a vector-like container with zero data copies of the actual container data this way... (it would be interesting though to have an STL wrapper object that does just this for all random access data types; call it something like sorted_wrapper.) :)

anonymous
Member #8025
November 2006

Quote:

Of course, vectors can easily win if you don't sort the actual array contents (you generate an sorted index->actual index mapping that happens to return items in sorted order). Completely avoids copy constructor overhead. Granted, this is not what is done in any STL container as far as I know, but it is possible to sort a vector-like container with zero data copies of the actual container data this way... (it would be interesting though to have an STL wrapper object that does just this for all random access data types; call it something like sorted_wrapper.)

For copy-expensive objects, you can sort a vector of pointers to the object. Although it is still questionable if it is worth the effort if list can do this without any extra work.
(I created an expensive class consisting of two ints and a string containing "Hello world", and overloaded comparison to sort it based on one of the randomly initialized ints. Then I sorted a vector of these objects, a vector of pointers and a list (identical data to the first vector). The results: sorting pointers ~3 x faster than first vector, sorting list ~5-6 x faster than a regular vector.)

Your idea is interesting, but wouldn't it produce massive overhead - no less than a list? Also, after sorting, wouldn't you still need to do the copying in one go (adds at least O(N) and seems tricky to do in-place)?

Anyway, I'm not saying list is better than vector per se (or the other way round). But a simple contiguous block of memory just doesn't suit well for all kinds of manipulations. Nor does any other data structure. So you have to make choices.

Finally, here's a link to compare the effectiveness of some operations with different containers. (Keeping in mind that O(N) can mean very different things with different containers.)

The rest of the site is interesting reading too!

Tobias Dammers
Member #2,604
August 2002
avatar

...and after all, keep in mind that STL containers are designed to use the same interface wherever possible, so if all is well, changing the container type for a given application later on shouldn't be too much of a problem. Just profile them against each other and see what's faster.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

 1   2 


Go to: