I have a bunch of old linux code which does something like this:
int size_of_buffer = /*stuff computed dynamically*/;
char *buffer = malloc(size_of_buffer);
recv(socket, buffer, size_of_buffer, 0);
//do some processing of the buffer as string
free(buffer);
When I was migrating it to C++ I changed it like this:
int size_of_buffer = /*stuff computed dynamically*/;
const auto buffer = make_unique<char[]>(size_of_buffer);
recv(socket, buffer.get(), size_of_buffer, 0);
const std::string str_buffer = buffer.get();
//do some processing on str_buffer
Which you can't fail to notice causes double memory allocation and potentially multiple copying of data. My idea now is to pass the pointer to first character of the std::string
with reserve
d storage, like this:
int size_of_buffer = /*stuff computed dynamically*/;
std::string buffer;
buffer.reserve(size_of_buffer);
recv(socket, &(buffer[0]), size_of_buffer, 0);
//do some processing on buffer
Is above code safe and well defined or there are some caveats and dangers that need to be avoided?
A similar question was asked here. The short answer is: it is not possible without copying.
Below C++17, there is no non-const
overload of std::string::data()
, and
1) Modifying the character array accessed through the const overload of
data
has undefined behavior.
Hence, you cannot modify the string through data
.
Since C++11,
data() + i == std::addressof(operator[](i))
for everyi
in[0, size()]
.
Therefore, you also cannot modify the string through &(buffer[0])
.
Before C+11, it is actually not very clear to me, what exactly is allowed, so maybe modifying through &(buffer.begin())
is ok, but I don't think so.
On cppreference, there is actually a quote that confounds me a bit
The elements of a basic_string are stored contiguously, that is, for a
basic_string s
,&*(s.begin() + n) == &*s.begin() + n
for anyn
in[0, s.size())
, or, equivalently, a pointer tos[0]
can be passed to functions that expect a pointer to the first element of a (null-terminated (since C++11))CharT[]
array.
I think this means to const
array, since otherwise it would not fit to the rest of the documentation and right now I do not have the time to go through the standard.
Since C++17, your code is ok, if you use std::string::resize
instead of reserve
, since data()
only guarantees a valid range on [data(), data() + size())
(or you can just construct the string with the right size). There is no-non-copy way to create a string from a char *
.
You can use a std::string_view
, which has a constant constructor from char *
. It does exactly what you want here, since it has no ownership on the pointer and memory.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments