4

Is it possible to reserve space in a std::string and get a pointer to copy char data directly into it? I have to interface with a C library that returns strings by copying them into a char *. How can I set up a std::string so that the library can write directly into it, avoiding intermediate copies.

Hypothetical example how this could look like:

std::string mystring;
int strlen = foolib_get_string_size(fooval);
mystring.size(strlen); // assuming size() with arg exists and does reserve() and set size
foolib_string_to_char_buffer(fooval, mystring.data(), strlen); // abusing data() method for writing
diemo
  • 171
  • 1
  • 12
  • 3
    `mystring.size(strlen);`... what you want is `mystring.resize(strlen);` – kesarling He-Him Aug 27 '20 at 16:55
  • Does this answer your question? [How to create a std::string directly from a char\* array without copying?](https://stackoverflow.com/questions/6700480/how-to-create-a-stdstring-directly-from-a-char-array-without-copying) – g19fanatic Aug 27 '20 at 19:31
  • 1
    @g19fanatic: the content is indeed the same question, but the title is misleading (alluding to an _existing_ char * array). That's why it didn't show up in the searches. – diemo Aug 28 '20 at 10:37
  • While your title is less clear to me. – g19fanatic Aug 28 '20 at 15:42

1 Answers1

4

Is it possible to reserve space in a std::string and get a pointer to copy char data directly into it?

Yes. Use its resize() method to allocate the memory, and then use its data() method (C++17 and later), or its operator[], to access that memory.

I have to interface with a C library that returns strings by copying them into a char *. How can I set up a std::string so that the library can write directly into it, avoiding intermediate copies.

Like this:

std::string mystring;
int strlen = foolib_get_string_size(fooval);
if (strlen > 0)
{
    mystring.resize(strlen); // -1 if strlen includes space for a null terminator
    foolib_string_to_char_buffer(fooval, mystring.data()/*&mystring[0]*/, strlen);
}

Alternatively, std::string has constructors which can allocate memory, too:

int strlen = foolib_get_string_size(fooval);
std::string mystring(strlen, '\0'); // -1 if strlen includes space for a null terminator
if (strlen > 0)
    foolib_string_to_char_buffer(fooval, mystring.data()/*&mystring[0]*/, strlen);

Of course, this does require std::string's memory block to be allocated contiguously, which is only guaranteed in C++11 and later (but in practice, is done in just about all known implementations). If you are not using C++11 or later, and really want to be standards compliant, then you should use an intermediate buffer, such as a std::vector, eg:

std::string mystring;
int strlen = foolib_get_string_size(fooval);
if (strlen > 0)
{
    std::vector<char> myvector(strlen);
    foolib_string_to_char_buffer(fooval, &myvec[0], strlen);
    mystring.assign(&myvec[0], strlen); // -1 if strlen includes space for a null terminator
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Thanks! So the one-line answer seems to be: _Yes in principle_ since C++11 through &mystring[0], and _Yes officially_ since C++17 through data(). – diemo Aug 28 '20 at 13:12
  • 2
    @diemo more like, _Yes in principle_ before C++11 and _Yes officially_ since C++11 through `&mystring[0]`, and _Yes officially_ since C++17 through `mystring.data()`. – Remy Lebeau Aug 28 '20 at 14:18