【问题标题】:Constructors behaving strange with exception handling code构造函数对异常处理代码的行为很奇怪
【发布时间】:2013-03-11 04:41:45
【问题描述】:

ScreenShot #1: Sample(Sample&) {...) // 不使用“const”没有错误 ScreenShot #2:当不包含复制构造函数时,析构函数被调用了两次。

当我在 VC++2010 中运行这段代码时,我发现结果令人惊讶,请看一下:

#include <iostream>
using namespace std;

class Sample {
public:
   Sample() { cout<<"Sample().\n"; }
   // Sample (Sample&) { cout<<"Sample(Sample&).\n"; }
   ~Sample() { cout<<"~Sample().\n"; }
};

void fx() {
   throw Sample();
}

int _tmain(int argc, _TCHAR* argv[])
{
   try { fx(); }
   catch (Sample&) { cout<<"Caught Sample.\n"; }
   return 0;
}

请说明为什么在示例中不包含复制构造函数,析构函数被调用了两次。例如,如果我们在析构函数中释放堆,则这样做会导致 Abort()。

我也知道对象的副本是由抛出对象创建的,但为什么它不为此调用复制构造函数。

有关代码和输出,请参阅随附的屏幕截图。

【问题讨论】:

  • 首先,应该是class Sample { 而不是class Sample() {
  • 另外,复制构造函数应该采用 const 引用,否则会出现编译器错误。
  • 你能告诉我们你的真实代码吗?当我编译并运行它时,我只看到Sample() - Caught_Sample - ~Sample -。 (有和没有复制构造函数)
  • 您的代码正在运行并确认 Xymotech 所说的内容:ideone.com/oe1uDF
  • @ajay:查看析构函数打印的内容,并将其与输出进行比较。 程序员要有敏锐的眼光!

标签: c++ visual-c++ exception-handling constructor


【解决方案1】:

这似乎是 VC++ 编译器中的一个错误(功能?:)),它已经存在了一段时间(但是我没有任何链接可以直接支持此声明,我没有时间继续搜索。我想我自己也遇到过一两次。)这仍然发生在 VC++ 2012 中。

始终定义复制 ctor 是一种很好的编码习惯,即使您不使用它也是如此。这是The Rule of Three 的一部分。不过也有一些注意事项。

  1. VC++ 将在抛出时尝试执行复制 ctor 时使用对象的上下文而不是调用者。因此,即使标记为私有,它仍然可以访问。这可能是一个遗留问题,尽管我找不到任何具体的事实。

  2. VC++ 将允许在抛出时使用非常量参数的复制 ctor。这也是允许在移动范式实施之前转移资源的遗留问题。我只发现了一些模糊不清的事情。不,VC++ 似乎没有使用移动范例来抛出对象,所以如果你尝试实现移动构造函数,这种情况仍然会发生。

有关移动构造函数的更多信息,您可以查看here

请注意,微软似乎会根据 C++ 标准的哪一部分来选择它是否会破坏太多东西。出于这个原因,我认为我不想加入 M$ 的编译器开发团队。 :/

【讨论】:

  • 这种与标准的偏差是否记录在任何地方?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多