简体   繁体   中英

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

I am looking at the following code ( simplified ) and ask myself how safe is it 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;
}

the output is :

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

msg2 is written twice and it's what i expected since the static message variable remains in memory during the lifetime of the program and there is no memory reallocation, so what is written at msg1 address is replaced by the new content of msg2 .

However if the size of msg2 is bigger, there is an internal reallocation within std::string message variable and the output is :

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

but I guess that there is no guarantee that msg1 address will not be reused in the future, and so a new access to msg1 content might eventually display something different and not coherent.

Does this function needs to be written differently to make it possible to use it without the limitations shown above?

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

Yes, that is safe.

But it is not safe to use that pointer after it has been invalidated, which is what the shown program does. The pointer will be invalidated by an assignment in a successive call to that function, if it reallocates. So, the pointer is safe only until the next call to the function (that would cause reallocation).

Does this function needs to be written differently to make it possible to use it without the limitations shown above ?

The function has the described limitations, so of course it has to be written differently to not have those limitations.

The core problem of your approach is that you only have one static string, but want to store multiple strings while not throwing away any of the earlier 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();
}

While this works as you would expect, it is silly. Consider whether you really want to store all strings for the rest of the execution. If not, then static storage is not a solution.

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

The pointer obtained from c_str() may be invalidated by:

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

When you call operator= for the second time inside returnMsg() , msg1 is invalidated and using it is Undefined behaviour .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM