15

According to the statements made in the answers of these questions

.. in C++11 it should be possible to call a C API function which takes a char pointer to store the output like this:

str::string str;
str.reserve(SOME_MAX_VALUE);
some_C_API_func(&str[0]);

But is there now a legal way to set the size of the string to the length of the (null terminated) content inside the buffer? Something like this:

str.set_size(strlen(&str[0]));

This is a very unaesthetic abuse of std::string anyway I hear you say, but I can't create a temporary char buffer on stack so I would have to create a buffer in heap and destroy it afterwards (which I want to avoid).

Is there a nice way to do this? Maybe not reserving but resizing and calling erase() afterwards would do it but it doesn't feel nice neater..

Community
  • 1
  • 1
frans
  • 8,868
  • 11
  • 58
  • 132
  • Have you tried `resize`? – Kerrek SB Mar 30 '15 at 13:08
  • yes, but `resize()` seems to modify the content. At least when I `reserve()` the buffer and `resize()` it afterwards the string is empty afterwards. It seems to work together with `resize(SOME_MAX_VALUE)`. If someone convinces me that this is the most sophisticated approach I'm happy :) – frans Mar 30 '15 at 13:17
  • @frans , why don't you use std::array to set string size ?? – MCHAppy Mar 30 '15 at 14:00

2 Answers2

12

You should be using resize() not reserve(), then resize() again to set the final length.

Otherwise when you resize() from zero to the result returned by strlen() the array will be filled with zero characters, overwriting what you wrote into it. The string is allowed to do that, because it (correctly) assumes that everything from the current size to the current reserved capacity is uninitialized data that doesn't contain anything.

In order for the string to know that the characters are actually valid and their contents should be preserved, you need to use resize() initially, not reserve(). Then when you resize() again to make the string smaller it only truncates the unwanted end of the string and adds a null terminator, it won't overwrite what you wrote into it.

N.B. the initial resize() will zero-fill the string, which is not strictly necessary in your case because you're going to overwrite the portion you care about and then discard the rest anyway. If the strings are very long and profiling shows the zero-filling is a problem then you could do this instead:

std::unique_ptr<char[]> str(new char[SOME_MAX_VALUE]);
some_C_API_func(str.get());
Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
0

This was/is a known limitation of C++ until C++20.

From C++23 you can use resize_and_overwrite():

glades
  • 3,778
  • 1
  • 12
  • 34