How to return a std::string.c_str()

Solution 1:

What happens in this code is:

const char * returnCharPtr()
{
    std::string someString("something");
    return someString.c_str();
}
  1. instance of std::string is created - it is an object with automatic storage duration
  2. pointer to the internal memory of this string is returned
  3. object someString is destructed and the its internal memory is cleaned up
  4. caller of this function receives dangling pointer (invalid pointer) which yields undefined behavior

The best solution is to return an object:

std::string returnString()
{
    std::string someString("something");
    return someString;
}

When calling your function, DO NOT do this:

const char *returnedString = returnString().c_str();

because returnedString will still be dangling after the returned std::string is destructed. Instead store the entire std::string:

std::string returnedString = returnString();
// ... use returnedString.c_str() later ...

Solution 2:

In C++, the simplest thing to do is to just returna std::string (which is also efficient thanks to optimizations like RVO and C++11 move semantics):

std::string returnSomeString()
{
    std::string someString;

    // some processing...

    return someString;
}

If you really need a raw C char* pointer, you can always call .c_str() on the returned value, e.g.

// void SomeLegacyFunction(const char * psz)

// .c_str() called on the returned string, to get the 'const char*' 
SomeLegacyFunction( returnSomeString().c_str() );

If you really want to return a char* pointer from the function, you can dynamically allocate string memory on the heap (e.g. using new[]), and return a pointer to that:

// NOTE: The caller owns the returned pointer, 
// and must free the string using delete[] !!!
const char* returnSomeString()
{
    std::string someString;

    // some processing...

    // Dynamically allocate memory for the returned string
    char* ptr = new char[someString.size() + 1]; // +1 for terminating NUL

    // Copy source string in dynamically allocated string buffer
    strcpy(ptr, someString.c_str());

    // Return the pointer to the dynamically allocated buffer
    return ptr;
}

An alternative is to provide a destination buffer pointer and the buffer size (to avoid buffer overruns!) as function parameters:

void returnSomeString(char* destination, size_t destinationSize)
{
    std::string someString;

    // some processing...

    // Copy string to destination buffer.
    // Use some safe string copy function to avoid buffer overruns.
    strcpy_s(destination, destinationSize, someString.c_str());
}

Solution 3:

As this question is flagged C, do this:

#define _POSIX_C_SOURCE 200809L
#include <string.h>

const char * returnCharPtr()
{
  std::string someString;

  // some processing!.

  return strdup(someString.c_str()); /* Dynamically create a copy on the heap. */
}

Do not forget to free() what the function returned if of no use anymore.

Solution 4:

Well, COVERITY is correct. The reason your current approach will fail is because the instance of std::string you created inside the function will only be valid for as long as that function is running. Once your program leaves the function's scope, std::string's destructor will be called and that will be the end of your string.

But if what you want is a C-string, how about...

const char * returnCharPtr()
{
    std::string someString;

    // some processing!.

    char * new_string = new char[someString.length() + 1];

    std::strcpy(new:string, someString.c_str());

    return new_string;
}

But wait... that's almost exactly as returning a std::string, isn't it?

std::string returnCharPtr()
{
    std::string someString;

    // some processing!.

    return new_string;
}

This will copy your string to a new one outside of the function's scope. It works, but it does create a new copy of the string.

Thanks to Return Value Optimization, this won't create a copy (thanks for all corrections!).

So, another option is to pass the parameter as an argument, so you process your string in a function but don't create a new copy. :

void returnCharPtr(std::string & someString)
{
    // some processing!.
}

Or, again, if you want C-Strings, you need to watch out for the length of your string:

void returnCharPtr(char*& someString, int n) // a reference to pointer, params by ref
{
    // some processing!.
}

Solution 5:

The best way would be to return an std::string, which does automatic memory management for you. If, on the other hand, you were really into returning a const char* which points to some memory allocated by you from within returnCharPtr, then it'd have to be freed by someone else explicitly.

Stay with std::string.