I have to interface with a C library in one of my programs, and I am writing a thin wrapper to use C++ types such as std::string. There are quite a number of functions that accept a char* and a maximum length as parameter and overwrite the memory pointed to by the char* with a zero-terminated C-string. Traditionally, I used a stack array and copied the data into a string manually.
std::string call_C_function(int x) {
char buf[MAX_LEN] = {0}; // MAX_LEN is defined by the library
size_t len = MAX_LEN;
C_function(x, buf, &len);
return std::string(buf, len);
}
I tried to avoid the copy and came up with a solution, but I don't know if this is strictly legal:
std::string call_C_function(int x) {
std::string buf(MAX_LEN, '\0'); // MAX_LEN is defined by the library
size_t len = MAX_LEN;
C_function(x, &buf.front(), &len);
buf.resize(len);
return buf;
}
This compiles and works, but I am having doubts because the std::string class makes it quite hard to get a non-const pointer to the character data. c_str() and data() both return const pointers. The standard forbids modifications of the buffer explicitly for these functions:
21.4.7.1: The program shall not alter any of the values stored in the character array.
From the documentation, it seems that this is legal because front() returns a reference to the first character of the buffer which must be continuous (I am using C++11/14). In 21.4.5, the semantics of front() is defined in terms of operator[](0) which does not forbid modifications.
Are there any issues with this approach from a language standard point of view? It seems that this would be a loop-hole allowing the modification explicitly forbidden in 21.4.7.1.
This is fine. You aren't allowed to modify the string via a pointer returned from a const member function but that doesn't mean you aren't allowed to modify the string at all. You have a non-const string, so you can modify it. In principle it's no different to doing s[0] = 'a'; s[1] = 'b'; etc.
It is forbidden to overwrite the final '\0' that is stored after the string data, but I assume from your example that MAX_LEN includes the space for the null terminator that is written by the C function, so the C function will only overwrite the string contents and not the extra character stored afterwards.
There is an open issue (LWG 2391) proposing to add a non-const std::string::data() which would be equivalent to &s.front(), and would give you direct access without making you concerned about going against the intention of the library.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With