Search code examples
c++debuggingmfcconst-char

C++ MFC missing const char* variable


So I have that simple code inside button click method:

std::stringstream ss;
unsigned counter = 0;
while(true)
{
    ss.clear();
    ss << DEFAULT_USER_CONFIG_NAME << " " << ++counter;
    const char* name = ss.str().c_str();
    MessageBox(name);

    /* ... while break condition */
}

The problem is that messagebox is empty. But it works correctly when I pass text directly:

MessageBox(ss.str().c_str()); // that shows text just fine

What I found with debugger is that local variable "name" is not created(at least it is not showing in debugger). Any clue why it is working when passed directly and failing otherwise? Also when i casted "name" to CString it returned true on IsEmpty() check.


Solution

  • The expression ss.str() creates a temporary std::string object. Storing the result of c_str() thus points to memory of a temporary, which quickly turns into a dangling pointer. Once the full expression statement

    const char* name = ss.str().c_str();
    //                                 ^ this is where the temporary ss.str() gets destroyed.
    

    is evaluated, the temporary gets destroyed.

    You already know, how to solve this, by placing the expression creating the temporary inside the full expression, that consumes it. This extends the lifetime of the temporary until the end of the full expression:

    MessageBox(ss.str().c_str());
    //                          ^ this is where the temporary ss.str() gets destroyed.
    

    The following illustrates the sequence of events. Let's just define a few placeholder classes and functions:

    void messagebox(const char*) {
        cout << "messagebox()" << endl;
    }
    
    struct tmp {
        tmp(const char* content) : content(content) { cout << "tmp c'tor" << endl; }
        ~tmp() { cout << "tmp d'tor" << endl; }
        const char* c_str() { return content.c_str(); }
    private:
        string content;
    };
    
    struct ss {
        tmp str() { return tmp("test"); }
    };
    

    With this in place, your first version

    ss s;
    const char* name = s.str().c_str();
    messagebox(name);
    

    produces the following output:

    tmp c'tor
    tmp d'tor
    messagebox()
    

    Whereas the second version

    ss s;
    messagebox(s.str().c_str());
    

    changes the sequence in the output:

    tmp c'tor
    messagebox()
    tmp d'tor
    

    (Live sample code)