Alf P. Steinbach wrote:
I did not pick that up in C, which I never learned. I like this more verbose
grep-able). Coming from Modula-2, I don't mind verbosity at all :-)
However, I was more interested in templates anyway (posted an
oversimplified piece of code). So what about these:
A (typedef)
===========
#include <iostream>
#include <ostream>
template < typename X>
struct Y {
X * x_ptr;
Y ( X * ptr = 0 )
: x_ptr ( ptr )
{}
~Y ( void ) {
delete x_ptr;
}
};
struct X;
typedef Y<X> YX;
struct X {
~X ( void ) {
std::cout << "crash me\n";
}
};
int main ( void ) {
YX yx ( new X );
}
Hm. Hm. I /think/ the template isn't instantiated until 'main' (i.e.,
the typedef doesn't do anything other than introduce a name), where the
definition of X is known, and so it should be OK.
However, there's also the practical matter of compilers that don't
implement two-phase template instantiation.
B (inheritance)
===============
#include <iostream>
#include <ostream>
template < typename X>
struct Y {
X * x_ptr;
Y ( X * ptr = 0 )
: x_ptr ( ptr )
{}
~Y ( void ) {
delete x_ptr;
}
};
struct X;
struct YX : public Y<X> {
I think that right here Y<X> is instantiated, with still incomplete type
X, and thus Undefined Behavior.
YX ( X * ptr = 0 )
: Y<X>( ptr )
{}
};
>
struct X {
~X ( void ) {
std::cout << "crash me\n";
}
};
int main ( void ) {
YX yx ( new X );
}
C (position of function definition)
===================================
#include <iostream>
#include <ostream>
template < typename X>
struct Y {
X * x_ptr;
Y ( X * ptr = 0 )
: x_ptr ( ptr )
{}
~Y ( void ) {
delete x_ptr;
}
};
struct X;
void f ( X * ptr = 0 ) {
Y<X> y ( ptr );
}
Instantiation with incomplete type X, Undefined Behavior.
struct X {
~X ( void ) {
std::cout << "crash me\n";
}
};
int main ( void ) {
f ( new X );
}
In my experiments with g++, all these programs print "crash me".
Hm, B and C "should", as far as I understand it, exhibit UB, which of
course means they could by chance print "crash me", but in practical
terms a compiler-generated empty X destructor should be invoked.
Checking...
I get the same result as your g++-testing by using MSVC 7.1. However,
using MingW g++ 3.4.4 B and C do not print anything (and warnings are
issued for the destructor calls), while A does print "crash me" (and no
warnings). This is consistent with g++ generally being much more
standard-conforming wrt. templates than MSVC.
Where is
the "point of deletion" in these programs when template instantiation
issues enter the picture? Which of the above have UB?
See above. I think I got it right; at least, testing above indicates
that. So, A is OK (A OK ;-)), while B and C are UB.
Thanks a lot. I also tried Comeau; and it agrees with your assesment.