I recently found the following code pattern in a C++ code base, and I am now wondering if it is safe according to the C++ standard. (The real code passed the const char*
pointer through several function layers, but I condensed it down to its essential form.)
#include <string>
class NetworkSocket
{
public:
void SetPort(const char* port)
{
m_port = port;
}
private:
std::string m_port;
};
int main()
{
const int port = 42;
NetworkSocket socket = {};
socket.SetPort(std::to_string(port).c_str());
}
Specifically, I want to know if the call to SetPort()
is safe, or if we are invoking undefined behavior, or accessing (potentially) deleted memory.
I tried to figure it out myself using cppreference, but got stuck in the definitions. I got as far as:
std::to_string()
returns a prvalue, thus creating a temporary object.c_str()
extends the temporary's lifetime. (At least since C++17, before I am not sure.)const char*
pointer undefined behavior. However, when I tried running the code through clang`s undefined behavior sanitizer no problems were found... https://godbolt.org/z/EfcvePoWePlease quote the relevant standard rules, and explain the differences between the standard versions (if there are any).
This is well-defined.
12.2 Temporary objects [class.temporary]
... Temporary objects are destroyed as the last step in evaluating the full- expression ([intro.execution]) that (lexically) contains the point where they were created.
1.9 Program execution [intro.execution]
... A full-expression is an expression that is not a subexpression of another expression.
Here:
socket.SetPort(std::to_string(port).c_str());
The temporary object is the std::string
object that's the return value from std::to_string
. The full-expression is, unremarkably, this entire expression. So the temporary object -- the one that owns its c_str()
-- gets destroyed after the call to SetPort()
returns. The End.
(there are two exceptions to this rule, they do not apply here).