5

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).

Community
  • 1
  • 1
rainer
  • 6,769
  • 3
  • 23
  • 37
  • 1
    You have UB in `return ss.str().c_str();` See: http://stackoverflow.com/questions/21034834/is-there-issue-will-stringstream-str-c-str – Hayt Sep 06 '16 at 08:21

1 Answers1

8

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.

Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
  • Thanks, that does make sense, I missed the point that `stringstream::str()` returned a the string as a copy. Is there any way to fix my `StringBuilder`, other than copying `ss.str()`'s result into another `string` in my class or using `(StringBuilder () << 1).str().c_str()`? – rainer Sep 06 '16 at 08:31
  • Why does [this](http://stackoverflow.com/questions/10006891/stdstringc-str-and-temporaries) say the opposite? Why are there two deleted answers here? – LogicStuff Sep 06 '16 at 08:49
  • 1
    @LogicStuff The linked question is different because in that situation, the temporary `std::string` isn't destroyed before the pointer is used. And I can only guess about the two deleted answers, but since they were both posted and deleted while I was writing mine, I would guess that they only looked at the line in `main`, saw nothing wrong with it, and then deleted their answers after seeing `Hayt`'s comment (also posted while I was writing my answer, and containing the core issue). – Sebastian Redl Sep 06 '16 at 08:56
  • @SebastianRedl Wow, even I've missed what `StringBuilder::c_str` is actually doing... – LogicStuff Sep 06 '16 at 09:00