c++castingchar-pointer

Value of const char* returns empty after construction


Casting this Vector3 into a const char* has worked in implicit and explicit conversions, but hasn't when attempting to convert it at construction time. Only then does const char* 'v3pchar' return blank. Any thoughts? The full code is below. Thanks!

#include <stdio.h>
#include <iostream>
#include <string>

using namespace std;

struct Vector3 {
    int x, y, z = 0;

    Vector3() {
        cout << "Vector3()" << endl;
    };
    
    Vector3(int X, int Y, int Z) : x(X), y(Y), z(Z) {
        cout << "Vector3(int X, int Y, int Z)" << endl;
    };

    // Focal point here
    operator const char* () {
        cout << "operator const char* called" << endl;
        v3string = to_string(x) + ", " + to_string(y) + ", " + to_string(z);
        v3pchar = v3string.c_str();
        return v3pchar;
    }

private:
    string v3string = "Never even blank";
    const char* v3pchar = "So why does this become blank?";
};

int main() {
    Vector3 v1 = Vector3(1, 2, 3);
    cout << "Vector3 implicit cast to char*: [" << v1 << "]" << endl; // Works

    const char* v2 = v1;
    printf("Vector3 explicit cast to char*: [%s]\n", (const char*)v2); // Works

    cout << "---------------------------------------------" << endl;

    const char* v3 = Vector3(4, 5, 6);
    cout << "Vector3 instantiation cast to char*: [" << v3 << "]" << endl; // Empty

    return 0;
};

Solution

  •    v3pchar = v3string.c_str();
    

    The const char * pointer returned by c_str() is owned by its std::string, and is only valid until the std::string is modified, or it gets destroyed, whichever comes first. Capsule summary: as soon as v3string is modified or destroyed, v3pchar is no longer valid.

       const char* v3 = Vector3(4, 5, 6);
    

    This results in the following sequence of events:

    1. A temporary Vector3 object gets created and constructed.
    2. Its operator const char* method gets called, and it returns a const char * owned by an internal std::string that's a member of the Vector3 object.
    3. The returned const char * is assigned to v3.
    4. The temporary Vector3 object gets destroyed, together with its std::string member.
    5. It follows the the originally-returned const char * pointer is no longer valid, since the std::string object that owns it is now destroyed.

    Any subsequent use of this const char * pointer results in undefined behavior.

    It should be possible to modify the shown code, using some features in modern C++ that would result in this construct becoming ill-formed (class method ref qualifiers), and having your C++ compiler catch this common bug. But that would be another question; as far as the reason for your observed results: it's undefined behavior for the reasons outlined above.