【发布时间】:2010-10-03 04:33:00
【问题描述】:
以下代码演示了我在 Turbo C++ Explorer 项目中遇到的一个奇怪问题。 D::D() 中的三个堆栈对象之一在超出范围后不会被销毁。
只有在发布模式下编译时才会发生这种情况,auto_ptrs a_ 和 b_ 的类型不同,并且抛出的异常不继承自 std::exception。它似乎在 VC++ 2005 和 C++ Builder 2009 中运行良好。我确实安装了 BDS2006 更新 2、修补程序汇总和修补程序 12。
是我的代码还是编译器?你知道修复吗?不能在 VCL 项目中可靠地使用 auto_ptr 会很不方便。
#include <memory>
#include <stdexcept>
#include <iostream>
typedef std::exception my_error; // will work fine if replaced with line below
//class my_error : public std::exception {};
class A {};
class B {};
class C
{
public:
C(int id) : id_(id) { std::cout << "C::C() " << id_ << std::endl; };
~C() { std::cout << "C::~C() " << id_ << std::endl; };
private:
int id_;
};
class D
{
public:
D()
{
C c1(1);
C c2(2);
C c3(3);
throw my_error();
};
private:
std::auto_ptr<A> a_;
std::auto_ptr<B> b_; // will work fine if replaced with line below
// std::auto_ptr<A> b_;
// std::auto_ptr<C> c_; // see expected output
};
#pragma argsused
int main(int argc, char* argv[])
{
try
{
D d;
}
catch (...)
{
std::cout << "caught exception" << std::endl;
}
return 0;
}
预期:
得到:
得到(没有注释行'// std::auto_ptr<C> c_;'):
编辑:进行了建议的更改
编辑 2:
我刚刚用 C++ Builder 2007 (11.0.2902.10471) 对其进行了测试,它显示了同样的问题。只要我检查项目 -> 选项 -> C++ 编译器 -> 调试中的“调试信息”框,发布配置就会起作用。令我惊讶的是,启用“调试信息”后可执行文件变得更小(从 39.5 KB 降至 31.5 KB)。
编辑 3:
在 Turbo C++ Explorer (C++ Builder 2006) (10.0.2288.42451) 中,如果我取消选中项目 -> 选项 -> C++ 编译器 -> 调试中的“内联函数扩展 (-vi)”框,则发布配置有效。用以下代码替换第一行 (#include <memory>) 也可以正常工作。
#pragma option push -vi-
#include <memory>
#pragma option pop
【问题讨论】:
-
向 C 构造函数和析构函数添加一个额外的识别文本字符串来确定哪个没有被破坏可能会很有趣。我怀疑这是第一个,因为这是本地堆栈上的第一个。我的印象是一个对象留在堆栈上。
-
另外,如果你实例化三个 C 对象会发生什么?只会破坏两个,还是只是破坏堆栈上的第一个?
-
这很奇怪。就好像在抛出异常之前最后一个对象没有被放入堆栈......编译器是否允许您设置每个模块优化?如果是这样,请尝试有选择地关闭该代码区域的优化!
标签: c++ destructor c++builder