4

Currently I have a complex function that myself and our team are not wanting to refactor to utilize std::string and it takes a char* which is modified. How would I properly make a deep-copy of string::c_str() into a char*? I am not looking to modify the string's internally stored char*.

char *cstr = string.c_str();

fails because c_str() is const.

rubenvb
  • 74,642
  • 33
  • 187
  • 332
Nick Betcher
  • 2,026
  • 5
  • 19
  • 25

3 Answers3

8

You can do it like this:

const std::string::size_type size = string.size();
char *buffer = new char[size + 1];   //we need extra char for NUL
memcpy(buffer, string.c_str(), size + 1);
Michał Walenciak
  • 4,257
  • 4
  • 33
  • 61
  • 6
    *Please, please* use a correct type for the string size, eg. `std::string::size_type` or `std::size_t`. – syam Aug 28 '13 at 15:22
  • @syam ahh you are absolutely right :) – Michał Walenciak Aug 28 '13 at 15:24
  • 1
    Don't forget to delete it. Or better still, get `std::vector` to do that for you, and access the array as `v.data()` or `&v[0]`. Or even another `string`, if you don't mind borderline-undefined behaviour. – Mike Seymour Aug 28 '13 at 15:45
4

Rather than modify the existing function, I'd just create an overload that acts as a wrapper. Assuming the existing function is ret_type f(char *), I'd write the overload something like:

ret_type f(std::string s) { 
    return f(&s[0]);
}

Note passing s by value instead of reference, minimizing the effort expended to get a copy of the string.

In theory, this isn't guaranteed to work (i.e., a string's buffer isn't guaranteed to be contiguous) until C++03. In reality, that guarantee was fairly easy for the committee to add primarily because nobody knew of an implementation of std::string that did anything else.

Likewise, it could theoretically be missing the NUL terminator. If you're concerned about that possibility you could use return f(const_cast<char *>(s.c_str())); instead, or add an s.push_back('\0'); before the return:

ret_type f(std::string s) { 
    s.push_back('\0');
    return f(&s[0]);
}
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
1

The obvious solution is:

std::vector<char> tmp( string.begin(), string.end() );
tmp.push_back( '\0' );
function( &tmp[0] );

(I rather like Jerry Coffin's solution, however.)

James Kanze
  • 150,581
  • 18
  • 184
  • 329