Is it safe to return const char * from a function that uses static std :: string inside?

I review the following code (simplified) and ask myself how safe it is to use this returnMsg function:

 #include <iostream> using namespace std; const char *returnMsg(const char *msg) { static std::string message; message = msg; return message.c_str(); } int main(int argc, char *argv[]) { const char *msg1 = returnMsg("Hello world"); printf("msg1 = %p\n", msg1); cout << msg1 << endl; const char *msg2 = returnMsg("Good bye"); printf("msg2 = %p\n", msg2); cout << msg2 << endl; cout << msg1 << endl; return 0; } 

output:

 msg1 = 0x23a6028 Hello world msg2 = 0x23a6028 Good bye Good bye 

msg2 written twice, and this is what I expected, since the static message variable remains in memory during the program life cycle and there is no memory reallocation, therefore, what is written at msg1 is replaced with new msg2 content.

However, if msg2 larger, there is an internal redistribution inside the variable std::string message , and the output is:

 msg1 = 0x1cc6028 Hello world msg2 = 0x1cc6058 Good bye looooooooooooooooooooooooooooooooooooooooong Hello world 

but I think there is no guarantee that msg1 will not be reused in the future, and therefore new access to msg1 content may ultimately display something else and not consistent.

Does this function need to be written in different ways so that it can be used without the restrictions mentioned above?

+7
c ++
source share
2 answers

Is it safe to return const char * from a function that uses static std :: string inside?

Yes, it is safe.

But it is not safe to use this pointer after it has been declared invalid, which makes the program shown. The pointer will be invalid by assignment when calling this function sequentially if it is redistributed. Thus, the pointer is safe only until the next function call (which will lead to redistribution).

Does this function need to be written in different ways so that it can be used without the restrictions mentioned above?

The function has the described limitations, therefore, of course, it needs to be written differently so as not to have these restrictions.

The main problem with your approach is that you only have one static row, but you want to store multiple rows without discarding any of the previous ones. So it seems that you need a whole bunch of static strings:

 const char *returnMsg(const char *msg) { static std::forward_list<std::string> messages; messages.emplace_front(msg); return messages.front().c_str(); } 

As long as it works as you expected it is stupid. Think about whether you really want to keep all lines for the rest of the execution. If not, then static storage is not a solution.

+9
source share

The code above leads to Undefined Behavior. Just look at the c_str() documentation:

A pointer obtained from c_str () may not be valid:

  • Passing a non-constant string reference to any standard library function or
  • Calling non-constant member functions in a string , excluding the operator [], at (), front (), back (), begin (), rbegin (), end () and render ().

When you call operator= a second time inside returnMsg() , msg1 is invalidated and uses its Undefined behavior.

+3
source share

All Articles