solomon@crystal.UUCP (Marvin Solomon) (04/03/86)
At the top of page 165 of the C++ book (section 5.5.7), we find the following sentences: There is no equivalent feature enabling a destructor to decide if its object was created using 'new', nor is there a feature enabling it to decide whether it was invoked by 'delete' or by an object going out of scope. If knowing this is important, the user can store the relevant information somewhere for the destructor to read. Well, I guess this is not a bug but a feature, since it's so clearly documented :-), but it seems a shame, especially since the information is provided to the destructor, but the C++ programmer can't get at it. In the 1.0 implementation, if I declare struct node{ int val; node *next; ~node(); }; node::~node(){ // something } the compiler generates the following code: int _node__dtor( _auto_this, _auto__free ) register struct node *_auto_this ; int _auto__free; { /* something */ if (_auto_this) if(_auto__free) _delete((int *)_auto_this) ; } ; Note the second argument to _node__dtor(). Each occurence of "delete p", where p is of type (node *), translates to _node__dtor((struct node *)p, 1); whereas, at the end of a scope with an automatic variable f, the compiler generates _node__dtor((struct node *)&f, (int) 0); Thus the compiler tells the default destructor whether it was invoked by 'delete', but the information is hidden from the C++ programmer. That hardly seems sporting! The paragraph goes on to say Alternatively, the user can ensure objects of that class are only allocated appropriately. If the former problem is handled, the latter is uninteresting. In other words, if I never declare any variables of type 'node', but only 'node *', the destructor can assume every object is allocated in free store (and thus can safely link it onto a free list, or whatever). Allow me to suggest an alternative (and I claim much more reasonable) discipline: Never use the 'unary &' operator. Then the latter problem becomes much more interesting. The destructor can assume that if it was called by 'delete', it should save 'this' on a free list, but if it was called by a variable going out of scope, it doesn't have to do anything. I can't take credit for this idea--I stole it directly from Pascal. In Pascal, there are two disjoint classes of variable: automatic variables, which can be named but pointed to, and "heap" variables, allocated by new() and freed by dispose(). The former are automatically reclaimed by the runtime when they go out of scope, whereas the latter must be explicitly deleted by the programmer. This scheme suffers (as does free storage management in C++) from the dangers of uncollected garbage and dangling references, but at least it doesn't allow the stack to become corrupted by an attempt to dispose() an automatic variable. How about it Bjarne? Why not let me write node::~node() { if (free) { next = free_head; free_head = this; } } node::node() { if (this==0) if (free_head) { this = free_head; free_head = free_head -> next; } else this = (node *) new char(sizeof(node)); } The only argument I can see against this extension is that it introduces another reserved word (at least inside destructors). -- Marvin Solomon Computer Sciences Department University of Wisconsin, Madison WI solomon@uwisc ...{ihnp4,seismo,allegra}!uwvax!solomon