什么时候被认为是完整的?

Cpp*_*oob 8 c++ boost smart-pointers scoped-ptr incomplete-type

请考虑以下代码段.boost :: scoped_ptr的析构函数在main函数的末尾调用.析构函数使用boost :: checked_delete来解除分配封装的Widget指针.

#include <boost/scoped_ptr.hpp>
#include <iostream>

class Widget;
Widget *make_widget();

int main()
{  
  boost::scoped_ptr<Widget> sp(make_widget());
  // std::cout << sizeof(Widget) << std::endl;
}

class Widget
{
public:
  Widget() {}
  ~Widget() { std::cout << "Widget destructor called." << std::endl; }
};

Widget *make_widget()
{
  return new Widget;
}
Run Code Online (Sandbox Code Playgroud)

我希望这段代码无法编译,因为类Widget在scoped_ptr<Widget>调用析构函数时是不完整的.但是,这可以在g ++ 4.8和Visual Studio 2010上完全编译.请注意带有sizeof(Widget)main函数中表达式的注释语句.如果我取消注释它,它将无法编译暗示Widget在那一点必须是不完整的.

这种行为的正确解释是什么?

编辑:一些答案(现已删除)指向未定义的行为,但我希望在scoped_ptr析构函数中使用checked_delete 导致编译失败.FWIW,我正在使用Boost 1.55.

Ded*_*tor 4

\n

5.3.5 删除[expr.delete]

\n\n

5 如果要删除的对象在删除时具有不完整的类类型,并且完整的类具有非平凡的析构函数或释放函数,则行为未定义。

\n
\n\n

因此,您肯定会期望它是 UB,因为这Widget::~Widget()是不平凡的,并且您会期望 boost 中的安全保护会出错。

\n\n

现在,让我们进一步挖掘:

\n\n
\n

2.2 翻译阶段[lex.phases]

\n\n

8 已翻译的翻译单元和实例化单元的组合如下:[注:...]每个已翻译的翻译单元都经过检查以生成所需实例化的列表。[注意:这可能包括已明确请求的实例化(14.7.2)。\xe2\x80\x94end note ]找到所需模板的定义。包含这些定义的翻译单元的源是否需要可用是由实现定义的。[注意:实现可以将足够的信息编码到翻译的翻译单元中,以确保此处不需要源。\xe2\x80\x94end note ] 执行所有必需的实例化以生成实例化单元。 [ 注意:这些与已翻译的翻译单元类似,但不包含对未实例化模板的引用,也不包含模板定义。\xe2\x80\x94end note ]如果任何实例化失败,则程序格式错误。

\n
\n\n

您可以通过翻译阶段来保存:
\n翻译翻译单元,然后实例化模板...

\n

  • @CppNoob:可能不会。所有符合要求的实现都必须将模板实例化推迟到翻译结束。 (3认同)