[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference turris::c_plus_plus

Title:C++
Notice:Read 1.* and use keywords (e.g. SHOW KEY/FULL KIT_CXX_VAX_VMS)
Moderator:DECCXX::AMARTIN
Created:Fri Nov 06 1987
Last Modified:Thu Jun 05 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:3604
Total number of notes:18242

3571.0. "Repetitive instantiations of template and circular declaration inclusions" by BACHUS::SABLON (Mich�le Sablon, TP/IM Support Belgium 856-7238) Wed May 14 1997 13:20

C++ V5.6-06
Digital UNIX V4.0-B

    We've rerun a customer reproducer using this new F.T. version and it
    appears to fix the template re-instantiation problem unless is some
    cases. Effectively the rebuild of the target executable, without any
    change to sources, objects, libraries and/or repositories, show that
    some objects are re-instantiated by each C++ build.

    Customer's further investigations identify all those cases to be
    templates involved in header files with circular references, introduced
    to solve compilation problems of missing include files during the
    instanciation.

    I don't know if their original problem was a conceptual error or a
    product problem. But they made a guideline of the way they work and now 
    have performance problems.

    The question is about how to do it right ?!

    Below an explanation of that situation. Real reproducer is available
    here on a local system, but is ENORMOUS !

    As usually lost in all those stuff,
    Mich�le.
    
------

    Problem description from the customer:

    Management of includes can be really tricky, due to the instanciation
    mechanism used by DEC CXX for templates, and files that compile
    successfully can be impossible to link !

    Indeed, for compilation, classes appearing as template arguments only
    can be declared as forward only. The following with compile
    successfully:

    A.h:			#include "a_file.h"
				class B;

				class A {
					f( A_TEMPLATE<B> x );
				}

    Nevertheless, during the compilation, or as a result of a #pragma
    define_template statement, the compiler will generate a template
    instanciation file containing :
    - the include statements from the file in which the remplate was first
      encountered
    - the include statements of the template code
    - a dummy variable declaration
    It could result in something like:

    A_TEMPLATE_12TB.cxx:	#include "a_file.h"
				#include "A_TEMPLATE.cc"

				A_TEMPLATE<B> dummy;

    This file will be compiled as part of the link phase, and its
    compilation will fail, because B is an unknow type (in fact, the first
    attempt to call a method from B in A_TEMPLATE.cc will fail, and the
    compiler will locate the error in A_TEMPLATE.cc, which is not good hint
    to detect the problem...)

    A solution to this is to make sure you include B.h in A.h, although not
    required at compile time.

    A.h:			#include "a_file.h"
				#include "B.h"

				class A {
					f( A_TEMPLATE<B> x );
				}

    Unfortunately, applying widely this strategy leads to another problem,
    because it causes cyclic inclusion:

    B.h				#include "anotherFile.h"
				#include "A.h"

				class B{
					g( ANOTHER_TEMPLATE<A> t );
				}

    It will not compile, since the preprocessor will perform, compiling
    A.h, the following includes:

    - begin of A.h
	- include file a_file.h
	- begin include file B.h
		- include file anotherFile.h
		- attempt to include A.h, which is protected against
		  multiple inclusion: not performed
		- declare call B in which type A is unknown => ERROR

    This is, however, a quiet common situation, whenever two classes
    maintain symmetric pointers to each other (d_Ref<A> in B and reversly).

    The implemented solution to this is to have both the include directive
    and the forward declaration. In order to have the files both compiling
    and linking, the include files becomes:

    A.h				#include "a_file.h"
				#include "B.h"
				class B;

				class A {
					f( A_TEMPLATE<B> x );
				}

    B.h				#include "anotherFile.h"
				#include "A.h"
				class A;

				class B{
					g( ANOTHER_TEMPLATE<A> t );
				}

    This however only solves the problem to the point one class definition
    doesn't need full definition from the other class because in this case,
    the forward declaration wouldn't succeed in breaking the inclusion
    cycle.

    But it generates a strange compilation behaviour, regenarating related
    the template instantiations at each build, some times even several
    times.
    
- The end -----
T.RTitleUserPersonal
Name
DateLines
3571.1NotedDECCXX::MITCHELLThu May 15 1997 10:371
We're working on this issue.