I wrote this for Neal, and it was long enough I thought I would save it.
One of the programs i did at Vizolutions used std::string extensively and the parts that needed performance tuning were also the string intensive parts, so I've played around a lot with what performance effect std::string has.
There are two things to consider, how to pass strings and how to return strings. But first some general notes
Keeping track of char * is a pain in the neck, but obviously not unmanageable. Duplicating a string is slow, but not really as slow as its reputation suggests. And you need to consider the impact char * vs. std::string can have on time-to-market, especially for games. Under Moore's law, computers will increase in speed by 10% every 2.5 months. 5% every 1.2 months and 1% every week. So is char * really gonna speed the whole app enough to make sense?
Now, for passing strings as parameters. If the caller uses a string literal (or otherwise doesn't have a std::string around), then a char * is always faster (since no temp std::string object needs to be made). if the caller uses a std::string, then std::string & is almost always faster (because std::string knows its size and char* doesn't). My programs always use std::string throughout, but I use string literals a lot too. So I tend to have functions that normally take string literals use char *, and have everything else take std::string.
For returning strings, its really nice to be able to use the return value of a function. If the string is kept in a member variable, then returning a std::string & is the way to go (in a single threaded environment), and has no performance penalty over char *. Whenever char * is involved, you need to keep track of whose responsibility it is to free it. I consider that a major burden on development efforts, and think about using code generically. Its easy to say that when passing a char * as a parameter, the caller has to free it, and if the function wants to keep it, make a copy. But if you want to return a non-member variable as a char *, the caller has to free it. And if you want to return a member variable, the caller can't free it. So now there's a real headache, the caller needs to know something about the implementation of the function, or you need to have some strdup calls. If you have the strdup calls, you might as well use std::string (which might do copy on write which is better than the strdup). Using a function signature like this:
void f(std::string *ret_val)can help a lot, and can sometimes improve performance over allocating and returning a char *: if the string object the caller passes in is already allocated and large enough, no new allocation needs to be done.
Fundamentally, what you want to avoid is string copies. with char* the code to do string copies and the effort to keep track of ownership is more than you want to think about it, its like a little thing zaps you every time you want to do a string copy and that helps keep them to a minimum. std::string makes deep copies easy, and so they are easy to abuse. But they don't really make it that much harder to avoid copies. In conclusion, I think std::string can be used in ways that are almost as fast as char *, and in some cases faster. Since char * can get into hairy situations about ownership, I find that std::string is almost always worth the performance difference.