Search code examples
c++language-lawyerundefined-behavior

Temporary in a function call: UB?


Consider the following code, based on this answer:

#include <iostream>
#include <sstream>

class StringBuilder {
public:
    template <typename T> inline StringBuilder &operator<<(T const &t) {
        ss << t;
        return *this;
    }

    inline char const * c_str() {
        return ss.str().c_str();
    }

private:
    std::stringstream ss;
};

void foo(const char *x) {
    std::cout << x << std::endl;
}

int main() {
    foo((StringBuilder() << "testing " << 12 << 3 << 4).c_str());
    return 0;
}

Does calling foo() with the temporary StringBuilder's return value cause UB in any way?

The reason I'm asking is that the example above works great, but in real life I'm using a library that, amongst other things, contains logging facilities, and using this library I'll get incorrect output (the logging function takes my char* correctly but overwrites it internally, which caused me to believe that the memory is no longer valid).


Solution

  • Yes, but not because of what you perhaps think.

    The temporary StringBuilder in the function call is not destroyed until after foo returns, so that's fine.

    However, the c_str() method returns the result of calling .str().c_str(), and the temporary string returned by this str() is destroyed as StringBuilder::c_str() returns, which means that the pointer returned is invalid outside. Using this pointer causes UB.