diemo
diemo

Reputation: 181

Is it possible to reserve and copy into a std::string directly?

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

Upvotes: 4

Views: 1533

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 595412

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
}

Upvotes: 4

Related Questions