Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I have a method which returns the constant char pointer. It makes use of a std::string and finally returns its c_str() char pointer.

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

    // some processing!.

    return someString.c_str();
}

I have got a report from COVERITY tool that the above is not a good usage. I have googled and have found that the char pointer returned, would be invalidated as soon as someString meets its destruction.

Given this, how does one fix this issue? How to return char pointer accurately?

Returning std::string would resolve this issue. But I want to know if there is any other means of doing this.

like image 481
user3210526 Avatar asked Mar 11 '14 15:03

user3210526


People also ask

What does string c_str return?

The c_str method of std::string returns a raw pointer to the memory buffer owned by the std::string .

How do I return STD strings?

Try this: std::string * sp; std::string func() { std::string s("bla"); sp = &s; return s; } int main() { std::string s = func(); if(sp == &s) std::cout << "YAY"; else std::cout << "BOO"; } -- On my compiler (VS) It prints YAY.

What does c_str () mean in C++?

The c_str() method converts a string to an array of characters with a null character at the end. The function takes in no parameters and returns a pointer to this character array (also called a c-string).


4 Answers

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 ... 
like image 126
LihO Avatar answered Oct 03 '22 06:10

LihO


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());
}
like image 22
Mr.C64 Avatar answered Oct 03 '22 08:10

Mr.C64


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.

like image 32
alk Avatar answered Oct 03 '22 06:10

alk


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!.
}
like image 39
ArthurChamz Avatar answered Oct 03 '22 08:10

ArthurChamz