Re: Design question related to std::auto_ptr
On Mar 24, 9:12 am, "Alf P. Steinbach" <al...@start.no> wrote:
* Vladimir Jovic:
James Kanze wrote:
On Mar 23, 11:10 am, Vladimir Jovic <vladasp...@gmail.com> wrote:
Alf P. Steinbach wrote:
[...]
// file fr.cpp
#include<memory>
#include "hy1.hpp"
class Details;
class MyConcrete {
private:
std::auto_ptr<Details> details_;
};
int main() {
MyConcrete obj;
return 0;
}
// file hy1.hpp
class Details
{
public:
Details(int a );
~Details();
void inc();
int *b;
};
// file hy1.cpp
#include "hy1.hpp"
Details::Details(int a ) :
b(new int(a))
{
}
Details::~Details()
{
delete(b);
}
void Details::inc()
{
*b += 3;
}
As you can see, Details is in another translation unit, and
the compiler doesn't complain. What do I have to do to make
it complains?
PS Ignore missing guards and style
Not sure whether you can make the compiler complain (there's
no guarantee, that's the general nature of UB).
But above, by virtue of including [hy1.hpp] in the main file
[fr.cpp] you have the definition of Details in both
translation units. The definition of a class is not the
collection of member definitions. It is the 'class' thing with
declarations -- and sometimes inline definitions -- of the
members, and it tells the compiler among other things the size
of an instance and whether there is a user defined constructor
and/or a user defined destructor.
Formally, the issue is whether the type is complete or not. The
class definition makes the type complete.
Remove the #include in [fr.cpp], perhaps the compiler will
complain then;
G++ does complain in this case. (It's basically what I tried.)
anyway you then have formal UB, even if it's difficult to
think of a way the compiler could realize that and then
underhandedly making the program do silly things, especially
considering that you do not instantiate Details.
However, it's not difficult to imagine that the compiler doesn't
realize that there is undefined behavior, and generate code
which does the wrong thing. Most compilers are totally unaware
of most of the standard library, and treat std::auto_ptr just as
they would any other template definition. Without concepts or
such, there would no problem in the specialization of auto_ptr
itself---the class probably only contains a pointer to the type,
and the language allows pointers to incomplete types. If the
destructor is instantiated over an incomplete type, however, the
issue is different. The destructor almost certainly contains a
delete expression, and "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." If the type is incomplete, of
course, the compiler can't know whether it has a non-trivial
destructor or a deallocation function, of course---the compiler
can warn about a potential error, or it can assume that you know
what you are doing, and that the class doesn't have a
non-trivial destructor or a deallocation function. In practice,
what will doubtlessly happen (warning or not) is that the memory
will be freed, but the class' destructor won't be called.
Note that in the case of g++, the warning is not a result of
constraints. (G++ verifies a lot of the constraints in the
standard library, but constraint violations result in an error,
not a warning.) You get exactly the same messages with:
class Details {} ;
int
main()
{
Details* p = NULL ;
delete p ;
return 0 ;
}
And the message is exceptionally clear, ending with:
note: neither the destructor nor the class-specific operator
delete will be called, even if they are declared when the
class is defined.
If you ignore the message, or compile the code with a compiler
which doesn't warn, the destructor will not be called, even if
it is not trivial.
In the case of auto_ptr, of course, the formal rule is the one
that the type must be complete for all instantiations. This is
a global rule in the standard; I'm pretty sure it was a case of
no one having the time, or wanting to take it, to specify the
completion requirements on a class by class or function by
function basis. In practice, I think a "typical" implementation
of auto_ptr would work with an incomplete type, except for the
destructor, the assignment operator and the reset function; i.e.
those functions which are required to delete the pointed to
object.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34