The things that took me a while to figure out were .c_str() // for c-style strings and .begin() // for a pointer to the first char in the string
unfortunatly with C7 begin() in now "const def() const", so using it for a manipulatible pointer is not usful unless you cast away const'ness.
PMFJI but there are two subtle but nasty gotchas here which can cause bugs that can be rather a pain to detect and debug when they finally bite you -- which they will, believe me.
1. It is important to understand that iterators are NOT necessarily pointers and should NEVER be cast to pointers. Iterators can be, and often are, opaque objects with all sorts of clever stuff going on in their operator *() method. AFAIK the only template in the STL that /guarantees/ that its storage is in a contiguous memory block unique to each instance is vector<T>. Other templates, including string, are IIRC permitted to (a) share storage between instances when possible and (b) maintain their storage in a non-contiguous way, such as a b-tree. Therefore, casting begin() to a plain old pointer is a sure road to pain.
However there is a deliberate get-out clause for people who need to use legacy C APIs: for vector<T> ONLY, it's correct to use &v[0] (NOT v.begin()) as a pointer that can be passed to legacy C APIs.
2. It's not a good idea to manipulate a string's data behind its back. Many current STL implementations will break horribly if you do that. Consider for example implementations that do the copy-on-write optimisation -- this is becoming quite common nowadays. These implementations reference-count the string data and only allocate a new copy when you modify the string using one of the non-const string APIs. If you manipulate a string's data behind its back using a const_cast of a const API, you will modify /all/ strings sharing that data, including const strings. Very bad news, leading to very hard-to-diagnose bugs.
Moral: those APIs were declared const for a reason.
You may say, "but MY std::string implementation doesn't do copy-on-write, I've read the source."
To that I reply, "Fragile assumption! It doesn't do that /now/, but the implementors are quite entirely free (and IMHO rather likely) to to it in their next release. Not to mention if you adopt another STL distribution or port to another compiler or platform. In either case you'll have a major clean-up operation on your hands and you probably won't even know about it until the bug reports start coming in, since your const_cast has disabled the compiler warning that the STL designers put in to warn you about precisely this. The conversation with management could be rather embarrassing. Isn't it better simply to do it right the first time?"
Solution:
If you need to modify a std::string, the best way is of course to use the supplied STL APIs.
If for whatever reason that isn't possible and you need to use a legacy C API that only understands pointers, the best way is to copy the string to a std::vector<char>, which /is/ guaranteed to work exactly like a C array. Modify the vector, then copy it back to the std::string. Something like this (off the top of my head):
--------------------- using std::string; using std::vector;
void legacy_modify( char *data, size_t length ); // data is a not necessarily null- terminated
void modify_string_with_legacy_api( string& ioString )
{
vector<char> v( ioString.size() );
ioStr.copy( &v[0], ioString.size() );
legacy_modify( &v[0], v.size() );
ioStr.assign( &v[0], v.size() );
}
---------------------Note the use of &v[0] rather than v.begin(). &v[0] is /guaranteed/ to be a pointer to the modifiable data, v.begin() is /not/.
Scott Meyers covers this and many other gotchas in this book "Effective STL", which I cannot recommend highly enough. I fact I consider it required reading for STL programmers. For example, if you don't know "the swap trick" for efficiently releasing unused storage, then you /really/ should read this book. Fortunately Meyers has a very amusing and readable style.
<http://tinyurl.com/dw2s>
Meyer's book assumes a basic grounding in the STL, for which many people like Josuttis' "The C++ Standard Library: A Tutorial and Reference ".
<http://tinyurl.com/dw30>
I've also found <http://www.sgi.com/tech/stl/> very useful as a reference manual for the STL.
I'm sorry to have been such an awful bore, but much of my job is porting so I have first-hand experience of how nasty these gotchas can be to find and debug and I'm always keen to nip them in the bud.
Anyhow, I hope this is helpful, Richard.
-- Sailmaker Software: Programming and consultancy services. <http://www.sailmaker.co.uk/> PGP key: E88BA153 = 140D E231 73C5 CA24 CD48 FE4C BDA9 308C E88B A153
