14

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.

e.James
  • 116,942
  • 41
  • 177
  • 214
Artyom
  • 31,019
  • 21
  • 127
  • 215
  • Can't you simply templatize the toupper function allowing to use string iterators instead of pointers? – jalf Apr 17 '09 at 15:17
  • If I could I wouldn't ask. Think of I have a large 3rd pary library that may support unicode or other things and their api works with pointers. Because it is just cost to much to implement this as template. – Artyom Apr 17 '09 at 15:20
  • @jalf: I don't have the standard at hand, but I believe that std::to_upper is exactly what you propose. – David Rodríguez - dribeas Apr 17 '09 at 16:19

5 Answers5

22

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
  • 333,147
  • 50
  • 533
  • 760
  • Actually from the links I see C++03 does not require continuos memory, but in practice there is no other implementations. – Artyom Apr 17 '09 at 15:42
  • I know better than to doubt Sutter, but do anyone have a reference to &str[0] being required to yield a pointer to contiguous data? – jalf Apr 17 '09 at 15:47
  • 1
    According to Austern, accessing via operator[] requires the contiguous array, accessing via an iterator does not (so &str.begin() wouldn't). I wouldn't argue with wither Sutter or Austern, but I was still not confident enough that I put the "So, it seems" weasel words in. – Michael Burr Apr 17 '09 at 15:55
  • Ok I see what you are talking, I just try to find the reference to standard that says this. – Artyom Apr 17 '09 at 16:06
  • 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 Jun 04 '09 at 17:14
17

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

CTT
  • 16,901
  • 6
  • 41
  • 37
  • 7
    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 Apr 17 '09 at 15:11
  • @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. – C. K. Young Apr 17 '09 at 15:32
  • 1
    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 Apr 17 '09 at 15:36
  • 2
    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 Apr 17 '09 at 15:37
  • 1
    @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 Apr 17 '09 at 15:39
  • 8
    Why are you even worrying about these issues. Use an iterator and all the problems go away!! – Martin York Apr 17 '09 at 15:50
  • @MartinYork: How do I use an iterator with snprintf? – Fred Nurk Feb 07 '11 at 21:36
  • @Fred Nurk: Curious what snprintf() has to to do with this question at all since we are talking about iterating over elements of string so that they can be manipulated with algorithms! – Martin York Feb 08 '11 at 08:22
  • @MartinYork: How do I use iterators with the two parameter overload of std::ctype::toupper? – Fred Nurk Feb 08 '11 at 09:30
  • @Fred Nurk: As usual what! Nobody here is using std::ctype::toupper()! But you can use it the same way with an iterator as you can with a pointer. Work out one you have the other. – Martin York Feb 08 '11 at 19:23
  • @MartinYork: The function in the question cannot be used with an iterator. It is very common to work with libraries that cannot be used with unknown iterator types, and I just gave two examples from standard libraries. Burying your head in the sand with "Use an iterator and all the problems go away!!" is just naive and wrong. – Fred Nurk Feb 08 '11 at 19:25
  • @Fred Nurk: Your examples are bogus and irrelevant to the above discussion. And yes any statement that is taken out of context can be shown not to hold, but that's just childish. To me this is merely looks like a childish attempt at trolling because of a previous conversation we had. In the CONTEXT of this question iterators/pointers are interchangeable. Please feel to try the above code with iterators it works fine (assuming you template's the input parameters (its not a std function)) and has the advantage (over pointers into std string) that it has well defined behavior. – Martin York Feb 09 '11 at 17:07
  • @MartinYork: The function prototype shown is void toupper(char *first,char *last_plus_one);. Matching that prototype is neither bogus nor irrelevant. I currently use several functions (from third-party libraries, but I picked examples here from the stdlib) which require either writing into std::string without iterators or wrapping the functions entirely, and knowing when to do what is very much important – and that is the context of this question – rather than hand-waving away the problem with "just forget this and use iterators". – Fred Nurk Feb 09 '11 at 20:36
  • @MartinYork: I'm sorry you think it's linked, but I've been participating more and more on SO lately and I felt compelled to point out such incorrect and irrelevant advice when I found it (and I found this question because someone linked to it). That happened to be you twice in one week, but checking my activity will show I'm not targeting you. But even if I was, I've not used any personal attacks and have focused on the issues and content: wrong advice is wrong advice no matter who says it. – Fred Nurk Feb 09 '11 at 20:39
  • @Fred Nurk: Its not me that is hand waving. You have brought up completely meaningless examples to try an d prove something that does not exist for the current situation. My advice stands and is correct for this context. If you really had a point then provide a specific answer below that shows your point so that other can be bothered to vote on it. But I see that you are the kind of commenter that needs the last word. So please take the chance now as I bow out of the pointless discussion. – Martin York Feb 09 '11 at 21:54
  • What's wrong with the example in the question? void toupper(char *first,char *last_plus_one); – Fred Nurk Feb 10 '11 at 07:12
5

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
  • 257,169
  • 86
  • 333
  • 562
3

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
  • 7,092
  • 3
  • 36
  • 50
-2

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
  • 4,959
  • 9
  • 44
  • 76