Recently debug various access violation in the project, where this problem is more representative and can be solved by standard code standards.
The problem can be summarized in the following code:
1 classteststring2 {3 Public:4TestString (Const Char*input): m_value (input) {}5TestString (Constteststring&input): M_value (input.m_value) {}6 operator Const Char*()Const{returnm_value.c_str ();}7 stringm_value;8 };9 Ten voidMain () One { ATestString Teststr ("Stringa"); - Const Char* STRINGB ="STRINGB"; - Const Char* result =true?TESTSTR:STRINGB; the //Would result point to "Stringa"? -ASSERT (Result = =testStr.m_value.c_str ()); -}
In the above code, you can assume that ' result ' will point to ' testStr.m_value.c_str ', because we have overloaded ' operator Const char* () ',
In fact, if you run the above code, you will find that ' result ' finally points to a "random" memory address.
I opened the assembly code browser after I ruled out any problems around me:
Const Char* result =true?teststr:stringb;00ce9585 mov eax,100ce958a Test Eax,eax 00ce958c JE main+0b0h (0ce95d0h) 00ce958e Lea Ecx,[teststr] 00ce9591 push ecx 00ce9592 Lea ECX,[EBP-138h] 00ce9598 call teststring::teststring (0ce1659h) ... 00ce95da call teststring::teststring (0CE14DDH) ... 00ce9625 Call TestString::operator Char Const*(0ce105ah) ... 00CE964C Call TestString::~teststring (0ce14a1h) ... 00ce9670 Call TestString::~teststring (0CE14A1H)
Here you can see clearly that the compiler has replaced ' teststr ' and ' stringb ' with a temporary object of type ' teststring ' and then called ' operator Const char* () ' to convert the result to ' const char* ', However, these 2 temporary objects are automatically destroyed, so the results you get are also dangling pointer.
As for the solution, you can expect to change this:
Const Char* result =true?testStr.m_value.c_str (): STRINGB;0008504C mov eax,1 00085051Test Eax,eax00085053Je main+55h (085065h)00085055Lea Ecx,[teststr]00085058Call std::basic_string<Char,std::char_traits<Char>,std::allocator<Char> >:: C_str (081370h) 0008505D mov dword ptr [EBP-104h],eax00085063JMP main+5Eh (08506Eh)00085065mov ecx,dword ptr [STRINGB]00085068mov DWORD ptr [ebp-104h],ecx 0008506E mov edx,dword ptr [ebp-104h]00085074mov DWORD ptr [Result],edx
Avoid compiler generation of type conversions other than expected by explicitly calling ' Test.m_value (). C_STR () '.
But remember what I said at the beginning of this article, this problem can be avoided by very good code specification, the method we need to use here is ' explicit '. By defining the constructor with one parameter as ' explicit ', we can avoid the compiler's implicit invocation of the tagged constructor.
So here's what I suggested fix is, define your teststring:
class teststring{public: explicit teststring (constChar* Input): m_value (input) {} explicit teststring (const teststring& input): m_ Value (Input.m_value) {} operatorConstcharconst return m_value.c_str ();} string m_value;};
Then let's look at the new code generated by the compiler:
Const Char* result =true?teststr:stringb;00f23c3b mov eax,100f23c40 Test Eax,eax 00f23c42 JE main+74h (0f23c54h) 00f23c44 Lea Ecx,[teststr] 00f23c47 call teststring::operator Char Const*(0f21604h) 00F23C4C mov dword ptr [EBP-110h],eax 00f23c52 jmp main+7Dh (0F23C5DH) 00f23c54 mov ecx,dword ptr [STRINGB] 00f23c57 mov dword ptr [EBP-110h],ecx 00f23c5d mov edx,dword ptr [ebp-110h] 00f23c63 mov dword ptr [Result],edx
Case Close. :)
Traps for C + + constructors and compilers to generate code automatically