solomon@crystal.UUCP (Marvin Solomon) (03/28/86)
Summary: Under some circumstances, the destructor for a compiler-generated temporary is called, even if though the temporary is never initialized. Description: The C++ compiler sometimes allocates automatic variables for intermediate results in expressions. The destructor for such a variable is called "at the first opportunity, typically immediately after the statement in which it was created." [The C++ Programming Language, section 6.3.2, p. 174]. However, if the expression occurs inside a conditional expression (... ? ... : ...), it may happen that the temporary is only initialized in a branch of the conditional that is not executed. In such a case, the destructor is called on an unitialized object. The problem is that "after the statement" is not "the first opportunity". Repeat-by: Compile and run the following program: extern void printf(...); int flag = 0; struct node { int x,y; node(int i, int j) { x=i; y=j; } ~node() { printf("delete %x(%d,%d)\n",this,x,y); } }; node operator+(node a,node b) { return node(a.x+b.x, a.y+b.y); } node *copy(node& a) { return new node(a.x,a.y); } main() { node a(1,1),b(2,2); node *c; { node junk(17,17); } c = (flag ? copy(a+b) : 0); } The result is something like this: delete 7fffe5c4(17,17) delete 7fffe5c4(17,17) delete 7fffe5d8(1,1) delete 7fffe5d0(2,2) The first line is generated by the destruction of 'junk'. The third and fourth are are from 'a' and 'b'. The second line is an attempt to delete a temporary that is supposed to hold the result of 'a+b', but instead contains the left-over value of 'junk' since it is in the same place on the stack. Here is the C code generated by the last statement, edited for readability: { struct node _auto__I2 ; _auto_c = ( flag ? copy ( ( struct node * ) ( ( _auto__I2 = _plusFCnode__Cnode___(_auto_a, _auto_b )), ( & _auto__I2 ) ) ) : ( ( ( struct node * ) ( 0 ) ) ) ) ; { printf ( "delete %x(%d,%d)\n", ( ( struct node * ) ( & _auto__I2 ) ) , ( ( struct node * ) ( & _auto__I2 ) ) -> _node_x , ( ( struct node * ) ( & _auto__I2 ) ) -> _node_y ) ; ; } { printf ( "delete %x(%d,%d)\n", ( ( struct node * ) ( & _auto_a ) ) , ( ( struct node * ) ( & _auto_a ) ) -> _node_x , ( ( struct node * ) ( & _auto_a ) ) -> _node_y ) ; ; } { printf ( "delete %x(%d,%d)\n", ( ( struct node * ) ( & _auto_b ) ) , ( ( struct node * ) ( & _auto_b ) ) -> _node_x , ( ( struct node * ) ( & _auto_b ) ) -> _node_y ) ; ; } } -- Marvin Solomon Computer Sciences Department University of Wisconsin, Madison WI solomon@uwisc ...{ihnp4,seismo,allegra}!uwvax!solomon