469,602 Members | 1,727 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,602 developers. It's quick & easy.

gcc, class forward declarations and destructor calls

I once made my own smart pointer implementation for a project and
at one point fought to death to find a malicious bug. The program
was not working and I couldn't figure out why.
The source of the problem was that MSVC++ was not giving me a
warning even though it should have. The problem was that I was
creating a smart pointer from a forward-declaration of a class
which, it seems, makes it impossible for the smart pointer to call
the destructor of the class properly.
In other words, I had something like this:

class SomeClass;

class AnotherClass
{
SmartPtr<SomeClassptr;
...
};

After including the full declaration of SomeClass instead of just
forward-declaring it, it started working.

Now, I decided to try what gcc says about this. When I did, it was
way more informative. It said, among other things:

SmartPtr.hh:80: warning: possible problem detected in invocation
of delete operator:
SmartPtr.hh:80: note: neither the destructor nor the class-specific
operator delete will be called, even if they are declared when the
class is defined.

Ok, I can buy that. I assume this agrees with the C++ standard?

However, now comes the weird stuff: If I compile a test program
with gcc with either no optimizations or just with "-O" then it
indeed does not call the destructor of that class. However, if
I compile with "-O2" or higher, it *does* call the destructor!
(It still gives the warning, though.)

I even tried making SomeClass be derived from a base class with
a virtual destructor, and both destructors were properly called
when compiling with "-O2" (but none when compiling with "-O" or
without it).

I'm curious: Why?
Mar 5 '07 #1
3 3564
On Mon, 05 Mar 2007 14:37:55 +0200, Juha Nieminen wrote:
I once made my own smart pointer implementation for a project and
at one point fought to death to find a malicious bug. The program
was not working and I couldn't figure out why.
The source of the problem was that MSVC++ was not giving me a
warning even though it should have. The problem was that I was
creating a smart pointer from a forward-declaration of a class
which, it seems, makes it impossible for the smart pointer to call
the destructor of the class properly.
In other words, I had something like this:

class SomeClass;

class AnotherClass
{
SmartPtr<SomeClassptr;
...
};

After including the full declaration of SomeClass instead of just
forward-declaring it, it started working.

Now, I decided to try what gcc says about this. When I did, it was
way more informative. It said, among other things:

SmartPtr.hh:80: warning: possible problem detected in invocation
of delete operator:
SmartPtr.hh:80: note: neither the destructor nor the class-specific
operator delete will be called, even if they are declared when the
class is defined.

Ok, I can buy that. I assume this agrees with the C++ standard?

However, now comes the weird stuff: If I compile a test program
with gcc with either no optimizations or just with "-O" then it
indeed does not call the destructor of that class. However, if
I compile with "-O2" or higher, it *does* call the destructor!
(It still gives the warning, though.)
Sounds like you are invoking Undefined Behaviour - in which case all bets
are off and the compiler can do whatever it likes (including defrosting
your fridge). So not so much "weird", perhaps, as "irrelevant".
I even tried making SomeClass be derived from a base class with
a virtual destructor, and both destructors were properly called when
compiling with "-O2" (but none when compiling with "-O" or without it).

I'm curious: Why?
Who cares? It's UB. My guess might be that something gets inlined
somewhere or perhaps the order of some function calls is different between
the two cases.

--
Lionel B
Mar 5 '07 #2
JLS
On Mar 5, 8:08 am, Lionel B <m...@privacy.netwrote:
On Mon, 05 Mar 2007 14:37:55 +0200, Juha Nieminen wrote:
I once made my own smart pointer implementation for a project and
at one point fought to death to find a malicious bug. The program
was not working and I couldn't figure out why.
The source of the problem was that MSVC++ was not giving me a
warning even though it should have. The problem was that I was
creating a smart pointer from a forward-declaration of a class
which, it seems, makes it impossible for the smart pointer to call
the destructor of the class properly.
In other words, I had something like this:
class SomeClass;
class AnotherClass
{
SmartPtr<SomeClassptr;
...
};
After including the full declaration of SomeClass instead of just
forward-declaring it, it started working.
Now, I decided to try what gcc says about this. When I did, it was
way more informative. It said, among other things:
SmartPtr.hh:80: warning: possible problem detected in invocation
of delete operator:
SmartPtr.hh:80: note: neither the destructor nor the class-specific
operator delete will be called, even if they are declared when the
class is defined.
Ok, I can buy that. I assume this agrees with the C++ standard?
However, now comes the weird stuff: If I compile a test program
with gcc with either no optimizations or just with "-O" then it
indeed does not call the destructor of that class. However, if
I compile with "-O2" or higher, it *does* call the destructor!
(It still gives the warning, though.)

Sounds like you are invoking Undefined Behaviour - in which case all bets
are off and the compiler can do whatever it likes (including defrosting
your fridge). So not so much "weird", perhaps, as "irrelevant".
I even tried making SomeClass be derived from a base class with
a virtual destructor, and both destructors were properly called when
compiling with "-O2" (but none when compiling with "-O" or without it).
I'm curious: Why?

Who cares? It's UB. My guess might be that something gets inlined
somewhere or perhaps the order of some function calls is different between
the two cases.

--
Lionel B- Hide quoted text -

- Show quoted text -
It may be undefined behavior, but that doesn't mean that someone
cannot be curious as to what the compiler is doing. As such, it seems
like a reasonable question, even if others do not care. It seems to
me, however, that as this question is a compiler specific question, it
would be better asked in a forum geared to that particular compiler.

I would think that a better understanding of the operations of a
particular compiler would allow users of that compiler to better
understand issues which they may, or may not have, with that compiler.
Knowing what error cases a compiler will catch and report, and which
ones will be ignored, is of obvious use, if you use that compiler. It
may be undefined behavior, but a good compiler will catch and report
that. We are long past the stage where "garbage in - garbage out" was
acceptable to anyone but a newbie. The purpose of a compiler is to
make it easier for a developer to accomplish a given task. Defrosting
your fridge may be acceptable by the language definition, but it is
not acceptable for the implementation of the language. Generating a
warning, is.

MSVC++ has several warning levels as well as an option to catch
warnings that are only detectable when optimization is turned on. I
would make sure that the warning levels are at 4 and the other option
turned on. There is also some value is running programs through static
code analyzers such as PC-Lint, Fortify, Coverity, among others. You
will find errors in your program. This may be one of them.

Mar 5 '07 #3
On Mon, 05 Mar 2007 07:04:40 -0800, JLS wrote:
On Mar 5, 8:08 am, Lionel B <m...@privacy.netwrote:
>On Mon, 05 Mar 2007 14:37:55 +0200, Juha Nieminen wrote:
I once made my own smart pointer implementation for a project and
at one point fought to death to find a malicious bug. The program
was not working and I couldn't figure out why.
[snip]
However, now comes the weird stuff: If I compile a test program
with gcc with either no optimizations or just with "-O" then it
indeed does not call the destructor of that class. However, if
I compile with "-O2" or higher, it *does* call the destructor!
(It still gives the warning, though.)

Sounds like you are invoking Undefined Behaviour - in which case all bets
are off and the compiler can do whatever it likes (including defrosting
your fridge). So not so much "weird", perhaps, as "irrelevant".
I even tried making SomeClass be derived from a base class with
a virtual destructor, and both destructors were properly called when
compiling with "-O2" (but none when compiling with "-O" or without it).
I'm curious: Why?

Who cares? It's UB. My guess might be that something gets inlined
somewhere or perhaps the order of some function calls is different between
the two cases.

--
Lionel B
Please don't quote sigs.
>- Hide quoted text -
- Show quoted text -
or this stuff.
It may be undefined behavior, but that doesn't mean that someone
cannot be curious as to what the compiler is doing. As such, it seems
like a reasonable question, even if others do not care. It seems to
me, however, that as this question is a compiler specific question, it
would be better asked in a forum geared to that particular compiler.
Definitely. The OP's query was technically OT. Your commentary on the
other hand is, to my mind, borderline on-topic ;)
I would think that a better understanding of the operations of a
particular compiler would allow users of that compiler to better
understand issues which they may, or may not have, with that compiler.
Knowing what error cases a compiler will catch and report, and which
ones will be ignored, is of obvious use, if you use that compiler. It
may be undefined behavior, but a good compiler will catch and report
that.
As did one of the OP's compilers...
We are long past the stage where "garbage in - garbage out" was
acceptable to anyone but a newbie. The purpose of a compiler is to
make it easier for a developer to accomplish a given task. Defrosting
your fridge may be acceptable by the language definition, but it is
not acceptable for the implementation of the language. Generating a
warning, is.
Agreed. However in practice, since a compiler cannot possibly report every
instance of potentially UB, I believe it is actually dangerous to rely on
your compiler to detect badly-written or semantically incorrect code (and
bad form to whinge about it when your compiler fails to nanny you to
your satisfaction).
MSVC++ has several warning levels as well as an option to catch
warnings that are only detectable when optimization is turned on. I
would make sure that the warning levels are at 4 and the other option
turned on. There is also some value is running programs through static
code analyzers such as PC-Lint, Fortify, Coverity, among others. You
will find errors in your program. This may be one of them.
Sure, I always have my warning level turned up to 11 (and if possible set
my compiler to treat warnings as errors). But bugs still get through and
even if it makes me feel better I cannot in all honesty blame the
compiler for not spotting my own cruddy coding errors.

--
Lionel B
Mar 5 '07 #4

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

10 posts views Thread by Angus Leeming | last post: by
28 posts views Thread by Steven T. Hatton | last post: by
23 posts views Thread by Fabian Müller | last post: by
reply views Thread by Leslaw Bieniasz | last post: by
23 posts views Thread by mark.moore | last post: by
3 posts views Thread by cpisz | last post: by
9 posts views Thread by silversurfer2025 | last post: by
10 posts views Thread by =?Utf-8?B?TWF4IDFlNg==?= | last post: by
reply views Thread by devrayhaan | last post: by
reply views Thread by gheharukoh7 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.