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

匿名 (未验证) 提交于 2019-12-03 02:45:02

问题:

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.

回答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: return an object :

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


回答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.c_str() + 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()); } 


回答3:

As this question is flagged C, do this:

#define _POSIX_C_SOURCE 200809L #include   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.



回答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!. } 


回答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.



回答6:

Your options are:

Return std::string

Pass a buffer to returnCharPtr() that will hold the new character buffer. This requires you to verify the provided buffer is large enough to hold the string.

Create a new char array inside returnCharPtr(), copy the buffer into the new one and return a pointer to that. This requires the caller to explicitly call delete [] on something they didn't explicitly create with new, or immediately place it into a smart pointer class. This solution would be improved if you returned a smart pointer, but it really just makes more sense to return a std::string directly.

Choose the first one; return std::string. It is by far the simplist and safest option.



回答7:

The problem is that someString is destroyed at the end of the function, and the function returns the pointer to non-existing data.

Don't return .c_str() of string that could be destroyed before you use the returned char pointer.

Instead of...

const char* function() {     std::string someString;     // some processing!     return someString.c_str(); }  //...  useCharPtr(function()); 

use

std::string function() {     std::string someString;     // some processing!     return someString; }  //...  useCharPtr(function().c_str()); 


回答8:

You can pass in a pointer to your string, and have the method manipulate it directly (i.e., avoiding returns altogether)

void returnCharPtr(char* someString) {         // some processing!     if(someString[0] == 'A')        someString++; } 


回答9:

If you have the freedom to change the return value of returnCharPtr, change it to std::string. That will be the cleanest method to return a string. If you can't, you need to allocate memory for the returned string, copy to it from std::string and return a pointer to the allocated memory. You also have to make sure that you delete the memory in the calling function. Since the caller will be responsible for deallocating memory, I would change the return value to char*.

char* returnCharPtr()  {     std::string someString;      // some processing!.      char* cp = new char[someString.length()+1];     strcpy(cp, someString.c_str());     return cp; } 


回答10:

A solution which hasn't been evoked in the other answers.

In case your method is a member of a class, like so:

class A { public:     const char *method(); }; 

And if the class instance will live beyond the usefulness of the pointer, you can do:

class A { public:      const char *method() {         string ret = "abc";         cache.push_back(std::move(ret));         return cache.last().c_str();     } private:     vector cache; //std::deque would be more appropriate but is less known } 

That way the pointers will be valid up till A's destruction.

If the function isn't part of a class, it still can use a class to store the data (like a static variable of the function or an external class instance that can be globally referenced, or even a static member of a class). Mechanisms can be done to delete data after some time, in order to not keep it forever.



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!