简体   繁体   中英

Function for both C-style strings and c++ std::string

I have a function that manipulates a string, and I need it to work on both C-style strings, and C++ std::string:

// C-style overload
void TransformString(const char *in_c_string, char *out_string);
// C++ std::strings overload
std::string TransformString(const std::string &in_string);

In order to avoid redundant code, I can implement the actual algorithm in only one of them, and then have the other call it. So, if put the implementation in the C++ overloaded function, then the C-style function will look like:

void TransformString(const char *in_c_string, char * out_c_string) {
   std::string in_string(in_c_string);
   std::string out_string = TransformString(in_string); // call C++ std::string overload
   strcpy(out_c_string, out_string.c_str()); // unwanted memory copy
}

My question is: Can I do this (having the algorithm implemented in only one function) without the extra copy (from std::string internal buffer to the C-style string)? My first thought was to try and "steal" the buffer, like a string move constructor does, but upon searching the web it looks like there is no safe way to do this, as it is implementation specific. And if I write the algorithm in the C-style function, the problem is the same as in the C++ function I have to allocate space for the char* string, and then move it to the std::string object.
I must mention that I do not know the size of the resulting string before the transformation is completed.

Thank you.

EDIT

The size of the buffer is not a problem here (I know the max size and the function receives an allocated buffer). I cannot just return the std::string.c_str() because then the buffer would become invalidated when the std::string object would be destroyed (just after the return would occur). I have changed the name of the variable out_c_string. (thanks 0x499602D2)

As long as you know how big the output buffer needs to be you can create a std::string and resize it to the buffer size. You can then pass a pointer to the std::string buffer into the C-style overload.

#include <cstring>
#include <iostream>
#include <string>

void TransformString(const char *in_c_string, char *out_c_string) {
    size_t length = strlen(in_c_string);

    for (size_t i = 0; i < length; ++i)
        out_c_string[i] = '*';

    out_c_string[length] = 'a';
    out_c_string[length+1] = 'b';
    out_c_string[length+2] = 'c';
    out_c_string[length+3] = '\0';
}

std::string TransformString(const std::string &in_string) {
    std::string out;
    out.resize(100);

    TransformString(in_string.c_str(), &out[0]);
    out.resize(strlen(&out[0]));

    // IIRC there are some C++11 rule that allows 'out' to
    // be automatically moved here (if it isn't RVO'd)
    return out;
}

int main() {
    std::string string_out = TransformString("hello world");

    char charstar_out[100];
    TransformString("hello world", charstar_out);

    std::cout << string_out << "\n";
    std::cout << charstar_out << "\n";

    return 0;
}

Here is a live example: http://ideone.com/xwVWCh .

You could try to get the c style string from a string class using c_str() . You'll have to do const_cast<char*> to remove the const.

This will only work if you don't need to reallocate the string (keep the same size).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM