Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is a type considered complete?

Consider the following code snippet. The destructor of boost::scoped_ptr is invoked at the end of the main function. The destructor uses boost::checked_delete to deallocate the encapsulated Widget pointer.

#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;
}

I expected this code to fail to compile as the class Widget is incomplete at the point the destructor of scoped_ptr<Widget> is invoked. However this compiles cleanly on g++ 4.8 and Visual Studio 2010. Note the commented statement with the sizeof(Widget) expression in the main function. If I uncomment it, it will fail to compile implying that Widget must be incomplete at that point.

What is the correct explanation for this behavior?

EDIT: Some answers (now deleted) pointed to undefined behavior but I would have expected the use of checked_delete in scoped_ptr's destructor to cause a compilation failure. FWIW, I'm using Boost 1.55.

like image 514
CppNoob Avatar asked Jul 19 '14 13:07

CppNoob


1 Answers

5.3.5 Delete [expr.delete]

5 If the object being deleted has incomplete class type at the point of deletion and the complete class has a non-trivial destructor or a deallocation function, the behavior is undefined.

Thus, you certainly would expect it to be UB, as Widget::~Widget() is non-trivial, and you would expect the safe-guard in boost to error out.

Now, let's dig higher:

2.2 Phases of translation [lex.phases]

8 Translated translation units and instantiation units are combined as follows: [ Note: ... ] Each translated translation unit is examined to produce a list of required instantiations. [ Note: This may include instantiations which have been explicitly requested (14.7.2). —end note ] The definitions of the required templates are located. It is implementation-defined whether the source of the translation units containing these definitions is required to be available. [ Note: An implementation could encode sufficient information into the translated translation unit so as to ensure the source is not required here. —end note ] All the required instantiations are performed to produce instantiation units. [ Note: These are similar to translated translation units, but contain no references to uninstantiated templates and no template definitions. —end note ] The program is ill-formed if any instantiation fails.

You are saved by phases of translation:
Translate the translation unit, then instantiate templates...

like image 134
Deduplicator Avatar answered Oct 14 '22 07:10

Deduplicator