Sign in to follow this  
valla2

c++: c-strings vs std::strings ( same thing for vectors!)

Recommended Posts

valla2    100
Why would someone prefer std::strings over cstrings in C++? Std::strings have more overhead than char*. Much more overhead. Allocate memory, allocate more memory and copy all the chars of the previous memory to it, deallocate the previous memory, do the same thing for a couple of times and deallocate the last memory you got. TOOOO much!! With c strings, you jut get your memory from your stack TOO fast, and that's all. YOu can also use memory from the heap IF you want, it's your choice. Exactly the same thing goes with arrays and vectors, with the difference that now the overhead of vectors is much more than that of std::strings, because they usually hold OBJECTS ( apart from ints and doubles ). And in game programming, performance is USUALLY everything. Security is an isue, yes, but if you are a good programmer it shouldn't be a problem. ...

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Not everyone writes games, but they generally have bosses who provide tight deadlines. That's why.

Have you done any testing of your own dynamic string / vector library vs. the std/STL versions that come with your compiler? How much faster are yours exactly?

Share this post


Link to post
Share on other sites
BiGF00T    435
Quote:
Original post by valla2
Security is an isue, yes, but if you are a good programmer it shouldn't be a problem.

What makes a person a good programmer?
1. ...
2. being immune to immense amounts of caffeine
3. ... (just some reasons including knowing how to learn from different resources and stuff)
4. to know whether the development time saving is worth much more than the very slight performance increase...
5. more stuff

I still use c strings a lot but only because I just switch to c++.
You can mess around with the c strings if you want but I guess it's not worth the time... I don't know many performance things where you need to use many strings... I use approximately 10 strings in my game. Most of them are in the menu and config load state and I don't think you need to take care of nanoseconds if you load a level or load the config file...?

Share this post


Link to post
Share on other sites
Telastyn    3777
std::strings are normal classes, rather than arrays [or pointers to arrays], and thus can be more easily returned from and passed into functions due to their difference how going in and out of scope effects them. std::strings allow for easier internationalization. Even good programmers are people, and make mistakes. std::string limits many of the possbilities for mistake.

You can just as easily store pointers in a vector. Once again, passing arrays to and from functions is painful at best. Passing vectors [or rather references to vectors] is not. Being restrained to fixed size arrays sucks in many ways.

Sure, good programmers -might- be able to write everything perfectly the first time through, but it's likely they won't. Spending time debugging is not fun, and prevents them from working on the -game-. Further, any major game these days [save Chris Sawyer's] is done by teams of programmers. Even if the good lead programmer gets it right the first time through, other likely less skilled programmers almost certainly won't when they modify the code for bug fixes or for their own modules.

Tracking down memory leaks or overflows is damned tedious, and generally difficult to reproduce. Saving that time means that programmers are suddenly free to do real optimization rather than saving a few cycles here and there for string allocation.

Share this post


Link to post
Share on other sites
valla2    100
How about this?:

struct Player {
Player( int ii) : i(ii) {}
int x, y, i;
double health;
long weapon;
double wait;
};

.....

vector<Player> vec:

for ( int i=0; i < 500; i++ ) // while(user_hits_enter)
vec.push_back( Player(i) );

.....

Player ar[500] = { 0 }; // before the game it's ok to wait, IF you are going to wait, but NOT in the game loop etc

i= 0;
while ( user_hits_enter ){
ar[i] = i+1;
++i;
}





fair?

Put the timers and check the results.

Share this post


Link to post
Share on other sites
Sneftel    1788
Your homework for tonight, valla2: explain why modern computer games are not written in assembly language (at least 5 reasons). Explain the process by which certain parts of a game eventually are rewritten in assembly, and how the decision to rewrite those parts is made. Explain how all this applies to std::string.

Share this post


Link to post
Share on other sites
Miserable    606
Quote:
Original post by valla2
Exactly the same thing goes with arrays and vectors, with the difference that now the overhead of vectors is much more than that of std::strings, because they usually hold OBJECTS ( apart from ints and doubles ).

Why? What's the time overhead beyond the initial object construction? What's the space overhead beyond a few pointers?

Quote:
And in game programming, performance is USUALLY everything.

Even in game programming, performance is not as important as correct execution, not to mention actually having a finished program to run.

Share this post


Link to post
Share on other sites
Promit    13246
Your two code blocks are not equivalent.


vector<Player> vec;
vec.resize( 500 );

//is equivalent to

Player arr[500];

//but is different from

for ( int i=0; i < 500; i++ )
vec.push_back( Player(i) );

//and you can allocate a memory block without invoking constructors like so:
vector<Player> vec;
vec.reserve( 500 );

Share this post


Link to post
Share on other sites
valla2    100
Quote:
Original post by Sneftel
Your homework for tonight, valla2: explain why modern computer games are not written in assembly language (at least 5 reasons). Explain the process by which certain parts of a game eventually are rewritten in assembly, and how the decision to rewrite those parts is made. Explain how all this applies to std::string.
assembly requires time.

cstrings and std::strings are pretty much equal here

Share this post


Link to post
Share on other sites
Oluseyi    2112
Your comparisons are inaccurate.

vector< Player > vec;
vec.reserve(500);


Know the library. You can customize std::string by using allocators. By default, it grows by 1.5 times (as does std::vector) when it needs to reallocate, and, as I indicated above, you can reserve memory.

Basically, your knowledge of the Standard Library is pitiful, which is why you make these deeply flawed comparisons.

Share this post


Link to post
Share on other sites
valla2    100
Quote:
Original post by Promit
Your two code blocks are not equivalent.

*** Source Snippet Removed ***

1) Even now they are not completely equivalent. .reverse() gets the memory from the heap which is more slow

2) Allmost all of the programmers who use vectors, are happy with the argument of not knowing the size of the vector before execution, and stick to push_back(). Reverse() is ok, but it seems it's not popular.

Quote:
Why? What's the time overhead beyond the initial object construction? What's the space overhead beyond a few pointers?

It's not just a few pointers. It's constuction, copy, destruction happening all the time

Share this post


Link to post
Share on other sites
Morbo    218
If that's your only example of STL not being performant enough, then I believe all you need to understand why people use it is more knowlege of HOW to use it. As Oluseyi already pointed out, the poor performance of your code was due to not using reserve() when you knew ahead of time how many elements would be added. If you read the docs on vector, it spells out quite clearly the performance characteristics and how to achieve optimal performance (reserve being only one technique among many).

In short: if you spend a little more time learning how to use STL properly, all your questions will be answered.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Quote:
Original post by valla2
How about this?:

*** Source Snippet Removed ***

fair?

Put the timers and check the results.


That code doesn't even make sense.

Share this post


Link to post
Share on other sites
Promit    13246
Quote:
Original post by valla2

1) Even now they are not completely equivalent. Vector .reverse gets the momory from the heap which is more slow


By your logic we should be using large stack arrays for everything we do, and that simply makes no sense.

Share this post


Link to post
Share on other sites
Jingo    582
std::string is nothing like a C character array. The only simularity is that at some level they both contain characters.

In practice std::string has less overhead than a char array. How do you typically read input into a character array? You allocate an array which is big enough to hold all the possible data that can be entered into the array. Since you rarely know exactly how much space is required, you typically end up not using anywhere near as much as you allocate.

std::string can grow and shrink depending on how much data is actually entered, it does this dynamically at run-time, and so does not require a huge unused buffer.

At its simplest level, indexing into an std::string will compile down to indexing into an array, though this depends on the implementation. Usually you should not see any difference between accessing string characters.

The syntax of std::string is also simpler than that of a char array. Passing and returning strings from functions is made a trivial task.

An std::string is more like a dynamic character array. To program the same funcionality would lead to messy un-exception-safe code. As an example, consider copying a dynamic C-string and an std::string


char* original = new string[amountneeded];
...
char* string = new string[amountneeded];
strcpy(string, original);
delete [] string;
delete [] original;

//or
std::string original;
std::string string = original;




I know which I prefer.

std::string also has the benefit of being able to encapsulate reference counting semantics, and internal stack allocated buffers, to speed up allocation of small strings.

So in reality, when you compare like for like, an std::string is going to be far quicker to use and use far less memory than any C-equavalent code that can be produced.

Share this post


Link to post
Share on other sites
Sneftel    1788
Quote:
Original post by valla2
assembly requires time.

cstrings and std::strings are pretty much equal here

Here's a code snippet that finds the substring "http://" in a string, replaces it with "ftp://", prepends "a@b" to it, appends ":21" to it, and converts it to uppercase. It does all of this in-place, is guaranteed not to leak memory, is guaranteed to be free of buffer overflows, and provides a weak exception guarantee.


void processString(std::string &str)
{
str.replace(str.find("http://"), 7, "ftp://");
str = "a@b" + str + ":21";
std::transform(str.begin(), str.end(), str.begin(), toupper);
}





Took me.... 40 seconds to write. Okay, now you do it in C, in a way that satisfies all the same guaranteees. Start.... nnnow.

EDIT: counted wrong. 30 seconds.

Share this post


Link to post
Share on other sites
valla2    100
Quote:
Original post by Morbo
If that's your only example of STL not being performant enough, then I believe all you need to understand why people use it is more knowlege of HOW to use it. As Oluseyi already pointed out, the poor performance of your code was due to not using reserve() when you knew ahead of time how many elements would be added. If you read the docs on vector, it spells out quite clearly the performance characteristics and how to achieve optimal performance (reserve being only one technique among many).

No, my code uses the loop
while ( user_hits_enter )
to add elements.
I used the for just for testing perpuses for your/my compiler.

Share this post


Link to post
Share on other sites
snk_kid    1312
Quote:
Original post by valla2
How about this?:

*** Source Snippet Removed ***

fair?

Put the timers and check the results.


Go and learn to how to effectively use the standard library infact go and learn C++ and large scale development properly before you start making assumptions & acquisitions because your attempt to prove otherwise was abysmal to say the least.

Note string literals are immutable.

Also note that all the standard library containers (and some non-container components) are templated by allocator type so you can provide custom allocation schemes that means your argument means nothing.

Share this post


Link to post
Share on other sites
Saruman    4339
I can't believe people still bring up arguments like this lol :)

First off std::string was made a C++ standard for a reason.. not because somebody just felt like throwing it into the library.

Second off, why the hell would you optimize something without having profiling data? In games when you profile I would really love for you to show me where you need more performance out of your strings and need to go to a C-string level compared to other components and blocks in the application.

Premature optimization kills projects, and especially stupid optimizations that don't make sense, kill safety, and still provide no noticable increase in performance.

Share this post


Link to post
Share on other sites
Telastyn    3777
Quote:
Original post by valla2
How about this?:

*** Source Snippet Removed ***

fair?

Put the timers and check the results.


Sure, we'll play this little game :D

After all, I just picked up Josuttis' book, and am working at learning the STL anyways.

Well, first off the array example doesn't even compile.

Here's what I used:

gdtest1.cc vector implimentation.

#include <stdio.h>
#include <stdlib.h>
#include <vector>

using namespace std;
struct player{
player(int ii):i(ii),x(0),y(0),weapon(0),health(0),wait(0){}
int x,y,i;
long weapon;
double health;
double wait;
};

int main(){
vector<player> playerlist(50000,player(0));
vector<player>::iterator it;
vector<player>::iterator end=playerlist.end();
int x;

for (it=playerlist.begin(),x=0;it!=end;++it,++x){
it->i=x;
}
}



gdtest2.cc array implimentation

#include <stdio.h>
#include <stdlib.h>

struct player{
player(int ii):i(ii),x(0),y(0),weapon(0),health(0),wait(0){}
int x,y,i;
long weapon;
double health;
double wait;
};

player *playerlist[50000];
int main(){
int x;

for (x=0;x<50000;++x){
playerlist[x]=new player(x);
}
}



But these event aren't exactly equivalent, as they [perhaps?] use different memory locations.

Anyways, compiled using gcc 3.3.3 with -O3 yields:


> time ./gdtest1
0.012u 0.012s 0:00.02 100.0% 0+0k 0+0io 0pf+0w
> time ./gdtest2
0.012u 0.024s 0:00.03 100.0% 0+0k 0+0io 0pf+0w


Or... no real difference.

Share this post


Link to post
Share on other sites
valla2    100
Quote:
Original post by Sneftel
Quote:
Original post by valla2
assembly requires time.

cstrings and std::strings are pretty much equal here

Here's a code snippet that finds the substring "http://" in a string, replaces it with "ftp://", prepends "a@b" to it, appends ":21" to it, and converts it to uppercase. It does all of this in-place, is guaranteed not to leak memory, is guaranteed to be free of buffer overflows, and provides a weak exception guarantee.

*** Source Snippet Removed ***
Took me.... 40 seconds to write. Okay, now you do it in C, in a way that satisfies all the same guaranteees. Start.... nnnow.

EDIT: counted wrong. 30 seconds.

I'll do it in C++ as the topic says, but with C strings:
void processString( char *str)
{
char s[] = "a@b";
strncpy(strstr( str, "htp://"), "ftp://");
strcat ( str, ":21");
strcat( str + strlen(s), str )
str[0] = 'a'; str[1] = '@'; str[2] = 'b'; //hehe i know i suck but i forgot the fucntions i could use...

std::for_each(str, str + stlen(str), toupper);
}[/quote]
It's been almost a year since i wrote code but that is the C++ program with Cstrings. The order of arguments passed in the functions could be wrong because i forgot, but that was my shot :)
s

Share this post


Link to post
Share on other sites
valla2    100
Telastin, that's not what i did in the "C" example. I didn't use "new"

Ok my the point on std:strings doesn't stands very well, especially since you just copy chars. But the point with vectors stands well.. i think

Share this post


Link to post
Share on other sites
valla2    100
>str[0] = 'a'; str[1] = '@'; str[2] = 'b'; //hehe i know i suck but i forgot the fucntions i could use...

ok i was too stupid, i should have more memory in 's' and say:
strcat ( s, str )
strcpy ( str, s ):

I know, it would be ugly

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.
Sign in to follow this