Directly modifying string contents

From this site's reference page on the string::data() method (http://www.cplusplus.com/reference/string/string/data/ ):

The returned array points to an internal location which should not be modified directly in the program.


In my program things would be much expedited if I could directly modify a string object's contents using the data() method. For instance:

((COMPLEXSTRUCT*)(String.data()+i))->member = 42;

Rather than:

1
2
3
4
COMPLEXSTRUCT temp;
String.copy((char*)&temp, sizeof(temp), i);
temp.member = 42;
String.replace(i, sizeof(temp), (char*)&temp, sizeof(temp));


The string object contains the contents of a file, and the insert() and replace() methods are much too convenient to use normal char arrays.

So my questions are, why shouldn't the contents of the string be directly modified using data(), and is there an easier way to do what I want?
Last edited on
I don't really understand what you're trying to do. Writing an int over string wouldn't result in anything good. Anyway, data() returns a const char* so you cant modify it. To modify a string use operator [], insert, replace and etc.
hamsterman wrote:
I don't really understand what you're trying to do. Writing an int over string wouldn't result in anything good.
yoonkwun wrote:
The string object contains the contents of a file



hamsterman wrote:
To modify a string use operator[]


http://www.cplusplus.com/reference/string/string/operator%5B%5D/
The function actually returns data()[ pos ].
The string object contains the contents of a file
Do you mean binary data? If so, string may not be the right choice. Use arrays or vector instead. I could be more helpful, if I knew what you're trying to do.

operator[] returns char&. data() returns const char*. You cannot assign to const char. Try it yourself.
I'd rather stick with string objects.

hamsterman wrote:
operator[] returns char&. data() returns const char*. You cannot assign to const char. Try it yourself.


I can assign values to the pointer returned by data():

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>

using namespace std;

int main()
{
  string str = "asdf";
  cout << str << endl;

  *((char*)str.data()+1) = 'b';
  cout << str;
}

asdf
abdf
Last edited on
I'm not sure I should try to help someone so full of himself as you are (but I'll give it a go anyway):

hamsterman very kindly asked you to clarify yourself, not simply repeat yourself because he was to dense to get it the first time through. Further, he knows the language and its implementation at least as well as you do. The fact is that you are not making much sense.

All extant implementations of the STL have data() and c_str() simply return a pointer to the internal data storage, so you can indeed do non-kosher things like modify it.

But the reason it is returned as a const reference is because the language permits some flexibility in implementation -- which is designed to accomodate future possibilities that we may be unaware of.

In your case, however, you appear to be trying to overlay types on memory anyway (something dangerous to do as it is). Simply cast as you have done.

1
2
3
4
COMPLEXSTRUCT* complex_struct( std::string& s )
  {
  return (COMPLEXSTRUCT*)(s.data());
  }
1
2
string myfoo( sizeof( COMPLEXSTRUCT ), 0 );
complex_struct( myfoo )->member = 42;

Remember that this assumes a POD struct, as C++ classes cannot be treated so cavalierly.

Remember also that the string will not be anything useful as a string. For conversions between 42 and "42" you'll want to look in to some proper object serialization.

Hope this helps.

[edit] I began responding before the last two posts, but was distracted until I could hit 'Submit' until now...
Last edited on
Well sorry if I gave that appearance. I don't see how I can further clarify myself in saying that I want to directly modify the contents of a string object using the pointer returned by string::data(), and asking why it's discouraged in the site's reference page. So concluding from your post I'm guessing that it's fine to modify values directly.
So concluding from your post I'm guessing that it's fine to modify values directly.


He actually said the exact opposite of that.
His code seems to do pretty much the same thing that mine does (i.e. use the pointer returned by data() to modify a value pointed by it). Except for some reason he used another function to do it. His code equals:

((COMPLEXSTRUCT*)(myfoo.data()))->member = 42;

As long as it doesn't produce unexpected behavior/crash it's fine with me.
I don't see the point... Can't he simply get each byte of the integer and then set it to each char of the string?
As long as it doesn't produce unexpected behavior/crash it's fine with me.


But it might produce unexpected behavior/crash when compiled (or run) on a different machine. It's a totally unsafe cast.


Disregard me.
Last edited on
From what I understand here, you want to set part of a string to an integer/other variable type? If so you should be able to use something similar to this:

1
2
3
4
5
6
7
void ModifyString(string& Modify, unsigned int SetAt, int SetTo)
{
	for(unsigned char i = 0; i < sizeof(int); i++)
	{
		Modify[SetAt + i] = ((char *) &SetTo)[i];
	}
}
Last edited on
I don't think there is a guarantee that the pointer returned by data() actually points to the internal data used by the string. After all it could be reference counted and writing to the internal data could modify more strings than you bargained for.

I would say its a definite no-no.

EDIT: The standard says that data() will return a pointer to a copy of the elements of the string.

cpp03 wrote:
21.3.1.5 data() points at the first element of an allocated copy of rlen consecutive elements of the string controlled by str beginning at position pos


EDIT: On further inspection point 21.3.1.5 is talking about the string from which this string is being constructed. However elsewhere it does explicitly state that the pointer returned by data() may not remain valid between member function calls and should not be written to:

cpp03 wrote:
21.3.6

const charT* data() const;
Returns: If size() is nonzero, the member returns a pointer to the initial element of an array whose first
3
size() elements equal the corresponding elements of the string controlled by *this. If size() is
zero, the member returns a non-null pointer that is copyable and can have zero added to it.
Requires: The program shall not alter any of the values stored in the character array. Nor shall the pro-
4
gram treat the returned value as a valid pointer value after any subsequent call to a non- const member
function of basic_string that designates the same object as this.

Last edited on
Topic archived. No new replies allowed.