标签:glin 问题 方案 oca 汇编 value explicit word res
最近在项目中debug各种access violation的,其中这个问题比较有代表性,并且能够被规范的代码标准解决。
问题可以总结为以下的代码:
1 class TestString 2 { 3 public: 4 TestString(const char* input) : m_value(input) {} 5 TestString(const TestString& input) : m_value(input.m_value) {} 6 operator const char*() const { return m_value.c_str(); } 7 string m_value; 8 }; 9 10 void main() 11 { 12 TestString testStr("StringA"); 13 const char* stringB = "StringB"; 14 const char* result = true ? testStr : stringB; 15 // Will result point to "StringA"? 16 assert(result == testStr.m_value.c_str()); 17 }
以上代码里面,你可以定认为`result`会指向`testStr.m_value.c_str()`吧,因为我们重载了`operator const char*()`,
其实不然,如果你运行以上的代码,你会发现`result`最后指向的是一个“随机”的内存地址。
我在排除了周围没有任何问题之后,打开了汇编代码的浏览器:
const char* result = true ? testStr : stringB; 00CE9585 mov eax,1 00CE958A 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)
在这里,你能够清楚的看到编译器把`testStr`和`stringB`都准换成了类型为`TestString`的临时对象,然后调用`operator const char*()`来吧结果转换为`const char*`,不过之后这2个临时对象都被自动销毁了,所以你得到的结果也成为了Dangling pointer。
至于解决方案,你估计可以想到这样改:
const char* result = true ? testStr.m_value.c_str() : stringB; 0008504C mov eax,1 00085051 test eax,eax 00085053 je main+55h (085065h) 00085055 lea ecx,[testStr] 00085058 call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::c_str (081370h) 0008505D mov dword ptr [ebp-104h],eax 00085063 jmp main+5Eh (08506Eh) 00085065 mov ecx,dword ptr [stringB] 00085068 mov dword ptr [ebp-104h],ecx 0008506E mov edx,dword ptr [ebp-104h] 00085074 mov dword ptr [result],edx
通过显式的调用`test.m_value().c_str()`来避免编译器生成预期之外的类型转化。
不过记得我在本文开始说的,这个问题可以通过很好的代码规范来避免,这里我们需要用到的方法是`explicit`。通过把带一个参数的构造函数定义为`explicit`,我们可以避免编译器对被标记的构造函数的隐性调用。
所以这里我所建议的fix是,这样定义你的TestString:
class TestString { public: explicit TestString(const char* input) : m_value(input) {} explicit TestString(const TestString& input) : m_value(input.m_value) {} operator const char*() const { return m_value.c_str(); } string m_value; };
然后我们来看看编译器生成的新代码:
const char* result = true ? testStr : stringB; 00F23C3B mov eax,1 00F23C40 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. :)
标签:glin 问题 方案 oca 汇编 value explicit word res
原文地址:http://www.cnblogs.com/asahi86/p/7437745.html