Search code examples
c++pointersinitializer-listc-str

Char pointer doesn't initialize as expected


MyClass.h

#pragma once

class MyClass {
public:
    const char* m_var;
    MyClass();
};

MyClass.cpp

#include <iostream>
#include <sstream>
#include "MyClass.h"

MyClass::MyClass() :
    m_var(("Text_" + std::to_string(5)).c_str())
{}

Main.cpp

#include <iostream>
#include "MyClass.h"

int main()
{
    MyClass myClass;
    std::cout << myClass.m_var;
    std::cin.get();
}

I was expecting program to output Text_5, instead it outputs:

╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ɽ÷Y╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠⌠ ╠╠╠╠╠╠╠╠


Solution

  • Don't do this. Don't attempt to store the result of std::string::c_str().

    Sub-expression

    "Text_" + std::to_string(5)
    

    produces a temporary std::string object, which is immediately automatically destroyed after the execution of the full expression

    ("Text_" + std::to_string(5)).c_str()
    

    When that object is destroyed, C-string "Text_5" pointed by c_str()'s result is destroyed as well. So, your m_var pointer ends up pointing to nowhere. What you see printed is garbage from that "nowhere". The behavior is formally undefined.

    For example, this will work "as expected"

    std::cout << ("Text_" + std::to_string(5)).c_str() << std::endl;
    // The temporary is destroyed at the end of the full expression. 
    // It lives long enough to make the above output succeed.
    

    But this won't

    const char *str = ("Text_" + std::to_string(5)).c_str();
    // The temporary is destroyed at the end of the above expression. 
    // Here it is already dead, meaning that `str` is an invalid pointer
    // and the output below will not work
    std::cout << str << std::endl;
    

    And this will work "as expected" again

    std::string s = "Text_" + std::to_string(5);
    const char *str = s.c_str();
    // Since `s` is not a temporary, it is not destroyed here, `str` remains 
    // valid and the output below works
    std::cout << str << std::endl;
    

    But in any case, don't try to use the result of c_str() for long-term storage. And if you are dealing with temporary objects, don't even think about storing it at all. It is intended to be used only for a moment, preferably within a single expression. If you store the pointer returned by c_str(), you risk suddenly discovering that it became invalid without you noticing. Formally it is possible to keep that pointer for a while as long as you really know what you are doing. But what you have above is a schoolbook example of when it fails.