我有一段相当简单的测试代码:
#include <stdio.h>
class PG
{
public:
PG(){
m_ptr = new int;
printf("Created PG %i\n", (int)m_ptr);
}
~PG(){
printf("Deleted PG %i\n", (int)m_ptr);
delete (m_ptr);
}
PG& operator =(const PG& src)
{
printf("Copied PG %i %i\n", (int)m_ptr, (int)src.m_ptr);
return(*this);
}
private:
int * m_ptr;
};
PG CreatePG()
{
PG ret;
return ret;
}
int main(int argc, char* argv[])
{
PG test;
test = CreatePG();
printf("Ending\n");
return 0;
}
如果我使用 GCC、VS2008 或 VS2012 进行全面优化编译并运行它,我会得到我所期望的结果:
创建 PG 7837600- 创建测试
创建 PG 7689464-创建 ret
复制 PG 7837600 768946-复制 ret 进行测试
已删除 PG 7689464-删除ret
Ending
已删除 PG 7837600-删除测试
然而,当我在没有优化的 VS2008 或 VS2012 上编译时,我得到这个:
创建PG 3888456- 创建测试
创建PG 4036144-创建 ret
已删除 PG 4036144-删除了 ret。等等,我们还没有复制它!
复制PG 3888456 4036144-我们现在正在尝试复制已删除的数据
已删除 PG 4036144-这已经被删除了。应用程序崩溃
我不敢相信这是 VS 中的一个从未修复过的错误,但我也看不出我做错了什么。在我的应用程序中,我有一个实例,在编译针对速度进行优化的更复杂的类时也会发生这种行为。我知道使用以下方法会更有效:
PG test = CreatePG();
但我仍然遇到类似的问题,尽管在这种情况下显然使用了复制省略:
创建PG 11228488
已删除 PG 11228488
Ending
已删除 PG 11228488
我仍然得到双重删除。
如果有人能对此有所启发,我将非常感激。
这是因为您的代码违反了三法则 http://en.wikipedia.org/wiki/Rule_of_three_%28C++_programming%29:由于您没有复制构造函数,因此在幕后发生了一些重要的事情,而您看不到打印输出。
当您没有复制构造函数时,C++ 很乐意为您定义一个复制构造函数。这通常是您想要的确切构造函数,但在一种情况除外:当您的类显式管理资源时。在这种情况下,当同一指针可以被多次删除时,逐字节复制内容会创建错误别名。当您打开优化时,编译器会跳过复制构造函数的调用(返回值优化)。然而,在关闭优化的情况下,复制构造函数被调用,然后m_ptr
被删除,留下指向已删除内存的实际指针。
以下是解决此问题的方法:
PG& operator =(const PG& src) {
*m_ptr = *(other->m_ptr);
printf("Assigned PG %x %x\n", (void*)m_ptr, (void*)src.m_ptr);
return(*this);
}
PG(const PG& other) {
m_ptr = new int;
*m_ptr = *(other->m_ptr);
printf("Copied PG %x\n", (void*)m_ptr);
}
注意:将指针转换为int
没有定义;你应该将指针转换为void*
,并打印%x
格式说明符。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)