Reputation: 3322
Given
#include <string>
#include <iostream>
struct A {
virtual operator std::string() const { return "A"; }
virtual operator const char *() const { return this->operator std::string().c_str(); }
};
struct B1 : public A {
virtual operator std::string() const { return "<"; }
};
struct B2 {
B2() { }
virtual ~B2() { }
virtual operator std::string() const { return ">"; }
virtual operator const char *() const { return this->operator std::string().c_str(); }
};
struct C1 : public A {
C1() { }
virtual ~C1() { }
virtual operator std::string() const { return "["; }
};
struct C2 {
C2() { }
virtual ~C2() { }
virtual operator std::string() const { return "]"; }
virtual operator const char *() const { return this->operator std::string().c_str(); }
};
int main() {
using namespace std;
cout << B1() << endl;
cout << C1();
cout << C2() << B2() << endl;
}
The output should be "<[]>". However, it is "<[]]".
Upvotes: 1
Views: 119
Reputation: 16046
Your problem really boils down to:
#include <string>
#include <iostream>
struct B2 {
B2() { }
virtual ~B2() { }
virtual operator std::string() const { return ">"; }
virtual operator const char *() const { return this->operator std::string().c_str(); }
};
struct C2 {
C2() { }
virtual ~C2() { }
virtual operator std::string() const { return "]"; }
virtual operator const char *() const { return this->operator std::string().c_str(); }
};
int main() {
using namespace std;
cout << C2() << B2() << endl;
}
Where it is evident that this has nothing to do with virtual functions. What happens here is that operator const char*
is called, which calls operator std::string
which returns a temporary std::string
from which you return the .c_str()
. Since after the call of operator const char*
this temporary std::string
is destroyed, you have a const char*
pointing to already freed memory.
And now anything can happen, since this is UB...
Upvotes: 3
Reputation: 500357
Actually, the behaviour of your code is undefined due to the following:
return this->operator std::string().c_str();
You're calling c_str()
on a temporary, and using the result later on.
What you're seeing is a valid manifestation of undefined behaviour.
Now, if you're curious as to what actually happens under the hood, you could modify the last line of main()
to read:
cout << (const void*)C2() << ' ' << (const void*)B2() << endl;
If you do, you'll probably see the same address getting printed twice (which in both cases is a dangling pointer). This is what happens on my computer, and I suspect what happens on yours. Of course, since the behaviour is undefined, this is just one possible manifestation of many.
Upvotes: 5