views:

692

answers:

5

In std::string there are only const members to fetch the data like c_str(). However I can get a reference to the first element of the string via operator[] and I can write to it.

For example, if I have function:

void toupper(char *first,char *last_plus_one);

I can write directly to vector getting a pointer to the first element:

vector<char> message // has "Some Message";
toupper(&message[0],&message[0]+message.size());

Can I do same thing with std::string?

string message="Some Message";
toupper(&message[0],&message[0]+message.size());

Does the standard guarantee that the location of the memory is actually linear? ie:

&(*(message.begin()+n)) == &message[n]

Thanks.

+10  A: 

std::string will be required to have contiguous storage with the new c++0x standard. Currently that is undefined behavior.

CTT
Is there known compiler that uses un-contigous strings? I.E. Can I relate on in 99% of cases (maybe just do work-arounds for specific compilers to prevent copy-overhead)
Artyom
I've always thought it would be 'neat' to have a compiler/library that was (excessively) pedantic about these types of things. It would do things the hard/inefficient/unexpected way while still being compliant.
Dan
@Dan: I believe Dinkumware and STLport both have a debug STL that caught all sorts of client non-compliance issues (and would emit warning messages). But I may be remembering things wrong.
Chris Jester-Young
It's almost certain to be contiguous - but std::string also stores things like the length which migth be invalid if you do this.
Martin Beckett
I seem to remember a Committee member (Sutter, most likely) being surprised that strings were not required to have contiguous storage by the Standard. They meant to have that requirement, it will be in the next Standard, and I don't know of any implementations that don't have contiguous string storage.
David Thornley
@Artyom: I don't know of any semi-current implementation that doesn't have contiguous storage. However, the extremely early releases of SGI's stl used storage that was similar to a deque.
CTT
Why are you even worrying about these issues. Use an iterator and all the problems go away!!
Martin York
A: 

I think that it gives you an undefined behavior. Use a stringstream to write to, and then use the str() member to get the string of the stream.

mslot
Wrong. You can write to a string.
Martin York
+18  A: 

Herb Sutter has this to say (http://herbsutter.wordpress.com/2008/04/07/cringe-not-vectors-are-guaranteed-to-be-contiguous/#comment-483):

current ISO C++ does require &str[0] to cough up a pointer to contiguous string data (but not necessarily null-terminated!), so there wasn’t much leeway for implementers to have non-contiguous strings, anyway. For C++0x we have already adopted the guarantee that std::string contents must indeed be stored contiguously. For details, see http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#530

And Matt Austern says similar in the referenced document (http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#530).

So, it seems that you can assume that once you call str[0] you do get a modifyable array of characters (but note that it is not required to be null terminated).

Michael Burr
Actually from the links I see C++03 does not require continuos memory, but in practice there is no other implementations.
Artyom
jalf
Michael Burr
Ok I see what you are talking, I just try to find the reference to standard that says this.
Artyom
I think both Austern and Sutter are implying that at least up to C++ 03, std::string does not need to be contiguous but no known implementations have it any other way. The bottom line is that the examples in the question are "undefined behaviour". Searching for "contiguous" or "[0]" from the beginning of the library section goes straight through the 'string' section and stops in 'vector'.
Richard Corden
+4  A: 

Yes you can modify a string.

You can also use it in algorithms that use iterators.

You can not use it in the same way as a vector<> because there is no guarantee that elements are in contiguous memory locations (yet: coming to a standard near you soon).

So if you modify your approach to use iterators rather than pointers it should work. And because iterators behave very much like pointers the code changes should be negligible.

template<typename I>
void toupper(I first,I last_plus_one)
{
    // Probably the same code as you had before.
}


{
     std::string  s("A long string With Camel Case");

     toupper(s.begin(),s.end());
}
Martin York
+2  A: 

As it has been pointed-out, one can use strings in algorithms that use iterators; the same case can be implemented using std::transform Ex:- consider a string 's' to be converted to lower case:

int (*pf)(int)=tolower; //lowercase
std::transform(s.begin(), s.end(), s.begin(), pf);

Regards,

Abhay