This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug c++/12737] New: Class destructor never gets invoked even though its corresponding class constructor is invoked, and the object has gone out of scope. (Appears to be related to copy-constructor initialization with an argument that consists of an implicit user-defined cast operator that returns a CONST value.)
- From: "da0g+ at cs dot cmu dot edu" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: 22 Oct 2003 22:49:32 -0000
- Subject: [Bug c++/12737] New: Class destructor never gets invoked even though its corresponding class constructor is invoked, and the object has gone out of scope. (Appears to be related to copy-constructor initialization with an argument that consists of an implicit user-defined cast operator that returns a CONST value.)
- Reply-to: gcc-bugzilla at gcc dot gnu dot org
PLEASE REPLY TO gcc-bugzilla@gcc.gnu.org ONLY, *NOT* gcc-bugs@gcc.gnu.org.
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12737
Summary: Class destructor never gets invoked even though its
corresponding class constructor is invoked, and the
object has gone out of scope. (Appears to be related to
copy-constructor initialization with an argument that
consists of an implicit user-defined cast operator that
returns a CONST value.)
Product: gcc
Version: 3.2.3
Status: UNCONFIRMED
Severity: critical
Priority: P1
Component: c++
AssignedTo: unassigned at gcc dot gnu dot org
ReportedBy: da0g+ at cs dot cmu dot edu
CC: gcc-bugs at gcc dot gnu dot org
GCC host triplet: Linux 2.4.20 #1-i686-001
GCC target triplet: i686-pc-linux-gnu
Under certain circumstances a class destructor is NEVER invoked, even
though its corresponding class constructor is invoked, and the object
has gone out of scope.
This creates problems with respect to smart pointers (and other
objects) that rely on matching constructor/destructor pairs.
This bug appears to stem from initializing the new object through
its copy constructor with a CONST value that is returned from an
implicitly invoked user-defined cast operator.
In the example code below:
FAILS: operator const Foo & () { return foo; }
FAILS: operator const Foo () { return foo; }
WORKS: operator Foo & () { return foo; }
WORKS: operator Foo () { return foo; }
Example code:
#define _CPP_BACKWARD_BACKWARD_WARNING_H
#include <iostream.h>
class Foo
{
public:
char placeholder;
Foo() { cout << "foo constructor\n"; }
~Foo() { cout << "foo DESTRUCTOR\n"; }
Foo(const Foo & theFoo) { cout << "foo COPY-constructor\n"; }
Foo & operator=(const Foo & theFoo){cout << "foo operator=\n"; return *this;}
};
class Charlie
{
public:
Foo foo;
Charlie() { cout << "charlie constructor\n"; }
~Charlie() { cout << "charlie DESTRUCTOR\n"; }
Charlie(const Charlie & theCharlie) { cout << "charlie COPY-constructor\n"; }
Charlie & operator=(const Charlie & theCharlie)
{ cout << "charlie operator=\n"; return *this;}
operator const Foo & () { return foo; }
};
static void bar ( Foo bar_foo )
{
cout << "bar\n";
}
#define POUT(X) cout << # X << endl; X
int main()
{
Foo foo;
Charlie charlie;
cout << endl << "Works fine:" << endl;
POUT ( bar ( foo ) );
cout << endl << "Works fine:" << endl;
POUT ( const Foo & f = charlie );
POUT ( bar ( f ) );
cout << endl << "Works fine:" << endl;
{
POUT ( Foo f2 = charlie );
POUT ( bar ( f2 ) );
}
cout << endl << "FAILS -- note the lack of DESTRUCTOR for bar_foo:" << endl;
POUT ( bar ( charlie ) );
cout << endl;
}
Example results:
% ./foo
foo constructor
foo constructor
charlie constructor
Works fine:
bar ( foo )
foo COPY-constructor
bar
foo DESTRUCTOR
Works fine:
const Foo & f = charlie
bar ( f )
foo COPY-constructor
bar
foo DESTRUCTOR
Works fine:
Foo f2 = charlie
foo COPY-constructor
bar ( f2 )
foo COPY-constructor
bar
foo DESTRUCTOR
foo DESTRUCTOR
FAILS -- note the lack of DESTRUCTOR for bar_foo:
bar ( charlie )
foo COPY-constructor
bar
charlie DESTRUCTOR
foo DESTRUCTOR
foo DESTRUCTOR