[Solved] Manipulating std::string


memset(data,0,1500); // This might not be correct but it works fine

It isn’t correct, and it doesn’t “work fine”. This is Undefined Behaviour, and you’re making the common mistake of assuming that if it compiles, and your computer doesn’t instantly catch fire, everything is fine.

It really isn’t.

I’ve done something which I wasn’t supposed to do!

Yes, you have. You took a pointer to a std::string, a non-trivial object with its own state and behaviour, asked it for the address of some memory it controls, and cast that to void*.

There’s no reason to do that, you should very rarely ever see void* in C++ code, and seeing C-style casts to any type is pretty worrying.

Don’t take void* pointers into objects with state and behaviour like std::string until you understand what you’re doing and why this is wrong. Then, when that day comes, you still won’t do it because you’ll know better.


We can look at the first problem in some fine detail, if it helps:

(void *)l_str.c_str()
  • what does c_str() return? A pointer to some memory owned by l_str
  • where is this memory? No idea, that’s l_str‘s business. If this standard library implementation uses the small string optimization, it may be inside the l_str object. If not, it may be dynamically allocated.
  • how much memory is allocated at this location? No idea, that’s l_str‘s business. All we can say for sure is that there is at least one legally-addressable char (l_str.c_str()[0] == '\0') and that it’s legal to use the address l_str.c_str()+1 (but only as a one-past-the-end pointer, so you can’t dereference it)

So, the statement

strRet((void *)l_str.c_str());

passes strRet a pointer to a location containing one or more addressable chars, of which the first is zero. That’s everything we can say about it.

Now let’s look again at the problematic line

memset(data,0,1500); // This might not be correct but it works fine

why would we expect there to be 1500 chars at this location? If you’d documented strRet as requiring a buffer of at least 1500 allocated chars, would it look reasonable to actually pass l_str.c_str() when you know l_str has just been default constructed as an empty string? It’s not like you asked l_str to allocate that storage for you.

You could start to make this work by giving l_str a chance to allocate the memory you intend to write, by calling

l_str.reserve(1500);

before calling strRet. This still won’t notify l_str that you filled it with 'a's though, because you did that by changing the raw memory behind its back.

If you want this to work correctly, you could replace the entirety of strRet with

std::string l_str(1500, 'a');

or, if you want to change an existing string correctly, with

void strRet(std::string& out) {
    // this just speeds it up, since we know the size in advance
    out.reserve(1500);
    // this is in case the string wasn't already empty
    out.clear();
    // and this actually does the work
    std::fill_n(std::back_inserter(out), 1500, 'a');
}

5

solved Manipulating std::string