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

Why would you program your own string class?(C++)

Started by CTar May 16, 2005 at 12:17 PM 174 replies 35.3k views
Original Post
CTar
CTar
Looking through the source of several open-source projects like Crazy-Eddies-GUI, Irrlicht etc. I have seen that most of these projects have their own string class. Why does they have this? I think it would be very hard to beat the STL one in performance. So why does they do it? Because some compilers(VC6 for example) doesn't have a good STL? or because they think they can do it better?
ITGER
ITGER
Good question! It seems like the "thing to do" on these boards is to reinvent the wheel and try to rewrite STL containers etc! And not for educational purposes either, that might actually be legitimate. Instead, people feel like they can come up with something better/faster, but what the write is of course non-standard so other people will have to learn how to use their damn code, rather than just look at it and immediately know how to use it.

Yay!
Basiror
Basiror
Hi

I think a lot of projects use older base code to work with and porting old code to use a new string class is a lot of work and actually of no use in most cases


also a lot of people aren t used to STL although you can consider it standard nowerdays


another thing to mention, you can replace the STL coming with the vc++ compiler
or just use the gcc compiler Mingw for windows


i personally stick with STL because i set on reuseability

http://www.8ung.at/basiror/theironcross.html
Telastyn
Telastyn
After learning a bit about standard string, I actually was suprised by its lack of functionality. stringstream allows for more functionality, but has its own series of quirks and limitations.

Add to that the fact that many libraries require [non-const] char arrays, it's a pain at times to use standard strings properly. So I can see where people might be tempted to rewrite a string class.

I imagine the original reasons were not so noble though.
Kylotan
Kylotan
The C++ string class lacks a lot of the niceties of strings in other languages, such as Python or Java. So it might be beneficial to write your own to overcome that. I have a project that uses my own string class, but I did implement it in terms of std::string.
_the_phantom_
_the_phantom_
Quote:
Original post by Telastyn
Add to that the fact that many libraries require [non-const] char arrays, it's a pain at times to use standard strings properly. So I can see where people might be tempted to rewrite a string class.


If its a C++ library and it requires char * as strings instead of taking std::string & I'd consider the library broken.
If its C library or an interface to another language I'd just write a small amount of glue code to get around the problem.

BrianL
BrianL
Quote:
If its a C++ library and it requires char * as strings instead of taking std::string & I'd consider the library broken.


While I appreciate the point in context, I have to take issue with that. One of the tenets of C++ is 'only pay for what you use'. Why should an interface force someone to use a class which requires dynamic allocations? What if the user wants to pass in a string in a string table? How about a string literal? You may also have to deal with different allocators, multithreading, etc. What someone wants to use your library on a platform without a std::string implementation, or with a broken/different one?

I use std::strings extensively, but like any other piece of code, there are tradeoffs to using them. Lets not let use of std::strings become dogma. There are very legitimate reasons to both use them and to avoid them, particularly in interfaces.
Jiia
Jiia
It's nice to have any feature you can think up in your system. It's nice to be in total control. String classes are very simple, though.

What about linked lists? Does anyone actually use the STL implementation? From what I understand of it, it can be extremely inefficient when working with big lists. Something about trying to move from node to node without an iterator.
Telastyn
Telastyn
Quote:
Original post by Jiia
It's nice to have any feature you can think up in your system. It's nice to be in total control. String classes are very simple, though.

What about linked lists? Does anyone actually use the STL implementation? From what I understand of it, it can be extremely inefficient when working with big lists. Something about trying to move from node to node without an iterator.


Despite the fact that linked lists -are- the main place where I've "re-invented the wheel", I still use std::list in places. It's better at doing things within the context of the data it contains.

And the use of homegrown linked lists is the classic example of people re-inventing the wheel for no good reason. In the majority of cases, a linked list is one of the worst container classes the programmer could've chosen.
_the_phantom_
_the_phantom_
Quote:
Original post by BrianL
While I appreciate the point in context, I have to take issue with that. One of the tenets of C++ is 'only pay for what you use'. Why should an interface force someone to use a class which requires dynamic allocations? What if the user wants to pass in a string in a string table? How about a string literal? You may also have to deal with different allocators, multithreading, etc. What someone wants to use your library on a platform without a std::string implementation, or with a broken/different one?

I use std::strings extensively, but like any other piece of code, there are tradeoffs to using them. Lets not let use of std::strings become dogma. There are very legitimate reasons to both use them and to avoid them, particularly in interfaces.


True, however the fact its a non-const char * implies that the string is going to be changed (and probably require reallocation of memory 'somewhere'), this brings up a whole host of issues ranging from when and where the memory is allocate to possible ownership issues.
So, while there might well be locations where a char * is required I'd argue that in the majortiy of cases a std::string & will serve you alot better.

Its all very well saying 'only pay for what you need', yet there is very very little difference in cost between a char * and a std::string &, both require dyamnic allocation 'somewhere', the difference between them is that std::string is alot safer.

As for your examples;
- a string table I'd probably impliment in terms of std::strings anyways
- string literals arent related to this really as char * implies memory which can be changed, literals are char const * const (or something like that) and thus shouldnt be reallocated or changed anyways.
- allocators might be a point, in that case you can fall back to std::strings parent class
- MT again might be a point but alot of libraries make no promises about thread safety anyways
- A platform without std::string is probably going to be too old to worry about and not C++, thus this is a non-problem. Plus you can install the std. lib. on old C++ compiles anyways (STLPort for example) and they shouldnt be 'different' as std::string is standard as is its interface, any changes make the platform broken (unless the standard changes) and thus not a library problem as it will be designed to conform with standard C++, not some broken system.

edit:
also, by using a char * the library in question is forcing me to adapt my program to its useage (while being unsafe at the same time) I'd consider that less acceptable than the library having an interface which uses safe and modern C++ constructs.

Also, on the topic of reinventing the wheel, the worse bit of all of these 'string' classes is that they probably arent compatible with each other, so you have to convert left, right and center to work with them if they are required for different libraries, where as if everyone had stuck with std::string all would have been good...
Staffan E
Staffan E
Apart from these work efficiency reasons there is one major reason to use "home-grown" implementations of the things that already exist. It's fun. It will take more time. It probably won't be nearly as fast as the standardized implementation. Still, it's a lot of fun writing code that works well. Much more fun that to use what has been written by someone else. That's all there is to it. The fun in programming.
Hack my projects! Oh Yeah! Use an SVN client to check them out.BlockStacker
_the_phantom_
_the_phantom_
true, but then if you didnt spend all that time on the libraries you could have fun making something new and impressive like a game instead of getting burnt out trying to do better than the standard lib. (beyond learning that is)
CoreMeltdown
CoreMeltdown
Quote:
Original post by staaf
... That's all there is to it. The fun in programming.


I absolutely agree.
And however.. of course people who worked at the stdlib have *A LOT* of experience, but for some simple string class usage, algorithms just remain the same: reallocation, concatenation, indexing, sub-string search.
For example, if you have to add contents to a string there are two cases:
1) string pre-allocated memory is enough
2) request some other memory
std:string just does theese ones. Coding them by ourselves won't let to worse performances (if we stay on standard memory allocation).
Anyway unfortunately i was asked to code on platforms (mobile) which at that time didn't supported stl library so i had to "reinvent the wheel".
What i'd wanted to say is that, even if stl is a DAMN FAST template library, it dowsn't mean you can't do >= in performances.

Not a polemic reply, just my opinion.

Marco.
Jiia
Jiia
Quote:
Original post by Telastyn
I still use std::list in places. It's better at doing things within the context of the data it contains.
...
In the majority of cases, a linked list is one of the worst container classes the programmer could've chosen.

If you use STL type lists, I can understand why you feel this way. Otherwise, there are plenty of good reasons to use linked lists. And I can only think of one good reason that they would be a bad choice; random access.

Lets take an item in a store for example. Character buys item, item travels store->character_inventory list. Character equips item, item travels character_inventory->hands list. Character tosses item, item travels hand->map list. All of these actions can be instantaneous with normal linked lists. STL lists requiring iterators do not function properly in these scenarios. You would have to scan each list to find the item. Not a big deal for this scenario, but it can definitely become a big deal.
Fruny
Fruny
Quote:
All of these actions can be instantaneous with normal linked lists. STL lists requiring iterators do not function properly in these scenarios.


WTF are you talking about? For all intents and purposes, syntax excepted, manipulating node pointers is equivalent to using iterators, without the safety guarantees.

You know you can store iterators in variables, right? The operations that invalidate a list iterator are, unsurprisingly, the same that would code a node pointer to 'go bad'.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
piccahoe
piccahoe
I make my own string class for knowlege of how a string class works and because I don't know how to use the string libary [embarrass]
==========================blog: http://piccahoe.phase1media.comCompany:http://phase1media.com
Jiia
Jiia
Quote:
Original post by Fruny
WTF are you talking about? For all intents and purposes, syntax excepted, manipulating node pointers is equivalent to using iterators, without the safety guarantees.

You know you can store iterators in variables, right? The operations that invalidate a list iterator are, unsurprisingly, the same that would code a node pointer to 'go bad'.


Heh, actually I don't. My first post pointed out what I thought was a problem with STL lists, and no one rejected it. So I assumed it was correct. To be honest, I've never actually used them.

So you only have to store the iterator, and not both the iterator and the object pointer? And an iterator can only go bad by deleting the object's memory? I didn't know that. Maybe STL lists are better than I thought.

edit: What about the case where an object may reference a node, and the node changes lists? The iterator is still valid?
Drew_Benton
Drew_Benton
Quote:
Original post by Jiia
Maybe the STL version is better than I thought.


*Chimes in* [wink]
coldacid
coldacid
Ogre::String is just a typedef for std::string (itself a typedef for std::basic_string) and if I'm not mistaken, CEGUI's string class is the same. Typedefing string in like that just makes it easier to type (String instead of std::string) while avoiding namespace pollution.
Fruny
Fruny
Quote:
Original post by Jiia
So you only have to store the iterator, and not both the iterator and the object pointer?


Some operations require manipulation of the data structure as a whole and thus is done with a list pointer. Sorting is an example (there is a list::sort member function). Most 'common' operations work with element ranges and can be done with iterators (look at the whole header!). Accessing elements is precisely an iterator's job. It would help you understand things if you tried to view an iterator as just a fancy pointer. Just like you can use pointers to manipulate data in arrays, you use iterators to manipulate data in lists, vectors, maps ... (in fact, conceptually, pointers are C-array iterators).

Quote:
And an iterator can only go bad by deleting the object's memory?


Off the top of my head, I don't think there are any operations, beside erasure, that invalidate a list iterator. When you so remove an element from a container, the iterator that pointed to it obviously becomes invalid.

Quote:
Maybe STL lists are better than I thought.


And you were there decrying it out of pure ignorance. [rolleyes] Many people think the STL is bad just because they've heard it was, and carry on spreading such a belief to new programmers... thus the cycle repeats.

Ok, I'll tackle your argument:

Quote:
What about linked lists? Does anyone actually use the STL implementation?


I do. Many other C++ programmers do. Heck, any C++ programmer should - why write a custom list class when you have a standard one? Imagine having to deal with each individual programmer idiosyncratic list code...

Quote:
From what I understand of it, it can be extremely inefficient when working with big lists.


You don't give library writers enough credit. There are commercial standard library implementations, including the one MS licenses for Visual Studio. Do you think they could get away with providing "extremely inefficient" code? They'd go out of business before the year ends.

You've got to realize that a STL list is a perfectly ordinary doubly-linked list. If a high-school student can write one, you can hope that a professional library writer can do a better job of it. It's not like they can really botch it anyway - not and pass their hiring interview (at least I hope).

Quote:
Something about trying to move from node to node without an iterator.


And with your custom implementation, how would you go from node to node without a node pointer? Yes, restarting from the beginning of the list every time under the pretense of providing random access is a common noob error.

Quote:
edit: What about the case where an object may reference a node, and the node changes lists? The iterator is still valid?


Depends on how "the node changes lists". Have a look at std::list::splice(). Check your documentation to see if it invalidates iterators. Personally, I doubt it does, that would be dumb.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan

Topic Locked

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

Sign in to reply to this topic.