473,406 Members | 2,954 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,406 software developers and data experts.

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 3809
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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

10
by: Angus Leeming | last post by:
Hello, Could someone explain to me why the Standard conveners chose to typedef std::string rather than derive it from std::basic_string<char, ...>? The result of course is that it is...
15
by: Mon | last post by:
I am in the process of reorganizing my code and came across and I came across a problem, as described in the subject line of this posting. I have many classes that have instances of other classes...
28
by: Steven T. Hatton | last post by:
I will assume many people reading this would never create anything similar to the example below. So let me preface this with _*IF*_ you were in a situation where you had to chose between using...
23
by: Fabian Müller | last post by:
Hi all, my question is as follows: If have a class X and a class Y derived from X. Constructor of X is X(param1, param2) . Constructor of Y is Y(param1, ..., param4) .
0
by: Leslaw Bieniasz | last post by:
Cracow, 16.09.2004 Hi, I have a problem with compiling the following construction involving cross-calls of class template methods, with additional inheritance. I want to have three class...
23
by: mark.moore | last post by:
I know this has been asked before, but I just can't find the answer in the sea of hits... How do you forward declare a class that is *not* paramaterized, but is based on a template class? ...
3
by: cpisz | last post by:
I have seen this on the top of a few header files class SomeClass; What does it mean? I would expect some sort of declaration or defintion following such as class SomeClass {
9
by: silversurfer2025 | last post by:
Hello everyone, I am currently having problems with a C++ abstract class. I have a class FrameWork.h which defines some methods (of which some are abstract, i.e. virtual void method() = 0). In...
10
by: =?Utf-8?B?TWF4IDFlNg==?= | last post by:
I have an application form named Form1.h. The code for this form is a namespace (MyNamespace) with two classes in it (Form1 and MyClass). Form1 has windows designer code and some button event...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.