Topic: VC++ virtual destructor bug?


Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Tue, 1 Mar 1994 01:39:20 GMT
Raw View
maxtal@physics.su.OZ.AU (John Max Skaller) writes:

[someone else writes:]
>>IBM's C Set ++ compilers produce the following warning for this code:
>>
>>  A pure virtual destructor needs an out-of-line definition in order
>>  for the corresponding class to be a base of another class.
>
> That diagnostic is INCORRECT.  A pure virtual destructor
>needs a definition to be used as a base of a class
>which is instantiated, although there's some doubt even about that
>if the object is never destroyed.
>
> That definition does NOT need to be given out of line, however.

I think by `out-of-line definition' they mean one that is not within the
class definition.  Sure, you can give a definition using an explicit
`inline' keyword, but it's not POSSIBLE to give a definition for a
pure virtual destructor inside the class definition.  The syntax just
simply doesn't allow it.

 class A {
  virtual ~A() = 0 {}; // syntax error
 };
 class B {
  virtual ~B() {} = 0; // syntax error
 };

>Nor is there any requirement unless the user
>defines an destructor in the derived class [...]

Agreed.

--
Fergus Henderson - fjh@munta.cs.mu.oz.au




Author: thomson@cppfs.torolab.ibm.com (Brian Thomson)
Date: 1 Mar 1994 20:37:41 GMT
Raw View
In article <CLo9AL.28B@ucc.su.oz.au>,
John Max Skaller <maxtal@physics.su.OZ.AU> wrote:
>>
>>  A pure virtual destructor needs an out-of-line definition in order
>>  for the corresponding class to be a base of another class.
>
> That diagnostic is INCORRECT. A pure virtual destructor
>needs a definition to be used as a base of a class
>which is instantiated, although there's some doubt even about that
>if the object is never destroyed.

Thanks for your comment.
We try to keep our messages brief while still adequately explaining the
situation, and we do sometimes overdo the brevity.

You're right that this situation isn't always an error, and that's why
this message, when it is emitted, is a warning.  There is a delicate
balance involved in serving users who know exactly what they're doing,
and don't appreciate "spurious warnings", while still managing to help
other users who would be severely confused if all they got was a linker
message saying
              "A::~A()": undefined external

I'll take your comment as a vote that we've swung too far in one direction.

>
> That definition does NOT need to be given out of line, however.

Probably a bad choice of words, it means "outside the class declaration".

> Compiler generated methods are supposed to be generated
>if, and only if, the methods are used.

I agree this is a sensible principle, and one we follow, but I'm not
aware of it being mandated anywhere.  Can you point me at a requirement
that says this?
--
Brian Thomson   THOMSON at TOROLAB
OS/2 C++ Development  thomson@vnet.ibm.com




Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Sun, 20 Feb 1994 19:43:48 GMT
Raw View
This isn't directly related to the C++ standard, but I just couldn't let
this go by without commenting.


In article <kitk.241.001000C0@mudshark.sunquest.com> kitk@mudshark.sunquest.com (Kit Kauffmann) writes:
> ----------------------------------------
>As far as not posting this to Compu$cam in the first place, why should I
>have to? If MS is going to do any support through e-mail, why not support
>Internet?...
>...
>Compu$cam is overpriced and inconvenient. They are actively working to end
>open communications in industry and education. I resent being told I have to
>work through a medium I fundamentally do not agree with and for which I can
>see no benefit or necessity.

I concur.

> --- Second e-mail message -------------
>
>>Hi Gregory,
>>
>>It is best to post supposed bugs on Compuserve in the appropriate
>>forum.  In this case MSLANG...

The audacity of vendors who expect you to pay for the privledge of telling
them about the defects in *their* products never ceases to amaze me.

Please note that this curious business practice is by no means limited to
Microsoft, nor is it even unique to the software industry. :-(

P.S.  These days, you can get 5-year full-replacement warrantees even on
such notoriously delicate things as disk drives.  I look forward to the day
when the software engineering profession will have advanced to the point
where similar levels of warranty protection will be offered, free of charge,
to consumers of software packges.  I may not live to see that day, but it
*will* come (eventually).

--

-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -




Author: kitk@mudshark.sunquest.com (Kit Kauffmann)
Date: Wed, 9 Feb 1994 16:00:04
Raw View
Posted By Kit Kaufmann for Gregory J. Peto:

I am posting an e-mail thread of correspondance with a member of Microsoft's Develper Relations Group (DRG). She relayed the original e-mail message to their languages group which she states to responded to her that my purported bug was "not a bug". I wou

Tammy's response to my second message (not included here) says she is not the
correct person to be sending complaints about the compiler or developer support
at MS. I was going to delete the "flame" in my e-mail message about
forcing Compu$cam down our throats, but since Tammy has since sent me to an 800
number and cannot provide another Internet accessible target, I have left the
flame in (sorry about that gals/guys, but Microsoft's whole approach to
technical support really steams me).

The three e-mail messages will make more sense read bottom to top. I have fixed
my original code to include the missing inheritance for class A in class B's
declaration.

If members of Internet C++ specific groups could please e-mail me directly a copy of
anything you might post related to this request I would appreciate it. These
are not groups I monitor full-time (too much traffic to keep up).

Thanks for your assitance,

Gregory J. Peto
gpeto@mudshark.sunquest.com

 --- Third e-mail message  ------------------------------------------------------------

Tammy Steele,

You are right on the missing declaration in my code. It should read
   class B : public A

I have worked in C++ for many years and understand it fairly well. I would
agree with your assessment of what the compiler is doing. However I still
maintain in several instances it is improper and at least illogical.

You state that declaring a pure virtual destructor should force the class
(class B in my example) to be treated as "abstract". However, MSVC does not
treat class B as being abstract. With every other compiler I have worked
with (CFRONT derived, IBM 6000 native, IRIX native) if you attempt to
instantiate an "abstract class" it generates a compiler error.  MSVC allows
you to create an instantiation of class B, using "new" for example. If the
compiler is recognizing class B as abstract, it should not let you do that.

I looked in Stroustrup, "The Annotated C++ Reference Manual", 1990 and could
find no statement that virtual destructors were "required" and could not be
trully "pure". I looked at the "Special Members" section on virtual
destructors and the various other sections on virtual member functions.
There is no mention of virtual destructors being treated in any way
different than other virtual functions.

Your statement that, "Pure virtual destructors must still be defined" does
not make sense. How can the compiler require a "pure" virtual function to
exist? Now perhaps the MSVC compiler chooses not to allow pure virtual
destructors (that all declared destructors must exist). If so, then it
should generate an error in the declaration:
   ~A() = 0;
If it allows this declaration of a "pure" virtual function, it cannot later
"require" it to exist. The meaning of the word "pure" (or the syntax
"function() = 0") means "this function does not exist."

The compiler generating an implied (and required) destructor for class B
makes sense if a virtual function declared in a parent class is not defined
for a child class. But the virtual function table of class B cannot generate
a symbol reference to a member function in class A that has been declared
"pure."

I am going to post this to comp.lang.c++ and comp.standard.c++ and see what
the Internet community thinks of this "non-bug." I'll post you on anything I
get back.
 ----------------------------------------
As far as not posting this to Compu$cam in the first place, why should I
have to? If MS is going to do any support through e-mail, why not support
Internet? My company has already invested a fair amount of money in high
speed connections to the Internet. Why should I be forced to take a step
back to the dark ages and have to use a modem to get technical support?

Compu$cam is overpriced and inconvenient. They are actively working to end
open communications in industry and education. I resent being told I have to
work through a medium I fundamentally do not agree with and for which I can
see no benefit or necessity.

My company has purchased dozens of C++ licensee even though half those are
rarely used. We all have ethernet and Internet access. Attempting to push
Compu$cam down our throats is another indication of MS bullying and ignorance.
For widely dispersed PC users Compu$cam may be a fine solution. But if you
want to work with "real" development organizations, this reliance on
Compu$cam shows poor judgement by MS and a deeper misunderstanding of the
market.

MS wants NT, and Microsoft as a whole, to be viewed as real competition to
UNIX, and to be viewed something more than a PC tool maker. If so, MS needs to
be willing recognize the standards of the scientific workstation/mini-computer
market which is clearly oriented toward Internet, not Compu$cam. Trying to
force a PC industry oriented approach, like Compu$cam, only further
emphasizes MS is not ready to join the "real" workstation and server world
and is just a PC OS tool maker trying to fit into britches too big for it.

If you personally do not want to provide e-mail technical support, fine. If
you cannot give me an e-mail address to use instead of yourself, then I will
route my queries through others in our organization that have a modem in
their box.

If Microsoft cannot provide Internet e-mail technical support I will not bother
trying to notify MS of problems such as my sample code point out and assume
MS is not "serious" about discussing seemingly obvious problems in the
compiler. And the next time I am sitting with the VP's discussing long term
technical strategies that include current alternatives to MS Windows, NT and
OLE, I will have yet another annecdote about how MS is not really serious
about breaking out of its PC beginnings.

 --- Second e-mail message -------------

>Hi Gregory,
>
>It is best to post supposed bugs on Compuserve in the appropriate
>forum.  It this case MSLANG.  I went ahead a passed it on to languages
>this time.  Here's what they said:
>
>This is not a bug.  Pure virtual destructors must still be defined.
>Declaring a virtual destructor to be pure simply forces the class to be
>abstract.  The derived class B (which the example misses the
>declaration of A as a base, but I presume that was the intent).  Class
>B has a compiler-generated virtual destructor, which references A's
>destructor.
>
>This requirement is not listed in the ARM, but it is specified in the
>current draft of the ANSI standard.
>
>Thank you,
>Tammy

 --- First e-mail message ---

>| From: Gregory J. Peto  <gpeto@mudshark.sunquest.com>
>| To: Tammy Steele
>| Subject: Apparent C++ bug: virtual destructor
>| Date: Wednesday, February 02, 1994 5:58PM
>|
>| I am sending this to you because I do not know to what e-mail
>| alias name at Microsoft to send reported bugs in the compiler.
>|
>| Problem:
>|
>| Visual C++ v1.5 accepts declaration:
>|
>| class A
>| {
>| public:
>|    virtual ~A() = 0;
>| };
>|
>| class B : public A
>| {
>| };
>|
>| Notice lack of "required" virtual destructor in child class.
>|
>| This compiles (as it should). However it lets me create an instance of class B and gives
>| a link time error: unresolved extern A:~A().
>|
>| 1) If MSVC accepts making the class A destructor "pure" and child class B does not
>| provide a version of pure virtual function from A the MSVC compiler should generate an
>| error when trying to instantiate an object of class B because B is an "abstract
>| class".
>|
>| 2) MSVC Should never generate reference to A::~A() since this is a "pure" function.
>|
>| I did not research this in Stroustrup to see if there were any special
>| exceptions for virtual destructors in comparison to other virtual
>| functions. If there is some special exception, it seems the compiler
>| should recognize it and generate an error message when trying to instantiate
>| an object of class B.


Kit Kauffmann   kitk@mudshark.sunquest.com (Internet)
                73363,447 (Compu$erve)
                (801) 277-5790




Author: thomson@cppfs.torolab.ibm.com (Brian Thomson)
Date: 10 Feb 1994 14:27:39 GMT
Raw View
Microsoft's developers are correct, and for exactly the reason they
give: B is not abstract because it has a compiler-generated destructor.

And yes, you do need to define A::~A() if you want to use A as a base
class.  IBM's C Set ++ compilers produce the following warning for this
code:

  A pure virtual destructor needs an out-of-line definition in order
  for the corresponding class to be a base of another class.


--
Brian Thomson   THOMSON at TOROLAB
OS/2 C++ Development  thomson@vnet.ibm.com




Author: pkt@lpi.liant.com (Scott Turner)
Date: Thu, 10 Feb 1994 15:11:01 GMT
Raw View
In article <kitk.241.001000C0@mudshark.sunquest.com>,
kitk@mudshark.sunquest.com (Kit Kauffmann) wrote:

> Posted By Kit Kaufmann for Gregory J. Peto:
>
> I am posting an e-mail thread of correspondance with a member of Microsoft's Develper Relations Group (DRG).

> >| Problem:
> >|
> >| Visual C++ v1.5 accepts declaration:
> >|
> >| class A
> >| {
> >| public:
> >|    virtual ~A() = 0;
> >| };
> >|
> >| class B : public A
> >| {
> >| };

A pure virtual function (such as A::~A()) may or may not be defined
somewhere in a program.

The compiler automatically generates a destructor for class B.  The
last thing this destructor does is call the destructor for its A part,
i.e. A::~A().  If the program contains a definition of A::~A() then all
will work fine.  If not, then there will be a link-time error.

> >| 1) If MSVC accepts making the class A destructor "pure" and child class B does not
> >| provide a version of pure virtual function from A the MSVC compiler should generate an
> >| error when trying to instantiate an object of class B because B is an "abstract
> >| class".

A destructor is a special case in which the child class need not explicitly
provide the member function by declaring and defining it.  The compiler
automatically provides one.  B is not an abstract class; there should be
no error message.

> How can the compiler require a "pure" virtual function to exist?

> >| 2) MSVC Should never generate reference to A::~A() since this is a "pure" function.

Not so. Any function that's declared pure virtual may be called with an
explicit-qualifier to suppress the virtual mechanism.  For example,

    class A {
    public:
        virtual void foo() = 0;
    };
    void A::foo() { }
    class B {
        B() { A::foo(); } // circumvents virtual table
    };

In this case the destructor for B needs to call the destructor for A in
the non-virtual sense.  MSVC is definitely correct on this point.

> You state that declaring a pure virtual destructor should force the class
> (class B in my example) to be treated as "abstract".

She didn't say that.

> Your statement that, "Pure virtual destructors must still be defined" does
> not make sense.

Pure virtual destructors are possible, but are not very useful just because
they invariably need to be defined.
--
Scott Turner
Liant Software Corp.
959 Concord St., Framingham, MA 01701  USA
(508)872-8700
pkt@lpi.liant.com




Author: hall_j@sat.mot.com (Joseph Hall)
Date: Fri, 11 Feb 1994 03:21:05 GMT
Raw View
Seems it was kitk@mudshark.sunquest.com (Kit Kauffmann) who said:
>Tammy's response to my second message (not included here) says she is not the
>correct person to be sending complaints about the compiler or developer support
>at MS. I was going to delete the "flame" in my e-mail message about
>forcing Compu$cam down our throats [...]

Obviously you are incorrect in your assessment of the bug, but I for
one agree that it would be good of MS to maintain an Internet support
presence, at least by email.

Has it occurred to anyone that perhaps they get a kickback from Compu$pend?

--
Joseph Nathan Hall | "Fetch the comfy chair!"
Software Architect |
Gorca Systems Inc. |                 joseph@joebloe.maple-shade.nj.us (home)
(on assignment)    | (602) 732-2549 (work)  Joseph_Hall-SC052C@email.mot.com




Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Fri, 11 Feb 1994 13:08:15 GMT
Raw View
kitk@mudshark.sunquest.com (Kit Kauffmann) writes:

>Posted By Kit Kaufmann for Gregory J. Peto (gpeto@mudshark.sunquest.com)
>
>>| Visual C++ v1.5 accepts declaration:
>>|
>>| class A
>>| {
>>| public:
>>|    virtual ~A() = 0;
>>| };
>>|
>>| class B : public A
>>| {
>>| };
>>|
>>| Notice lack of "required" virtual destructor in child class.
>>|
>>| This compiles (as it should). However it lets me create an instance of
>>| class B and gives
>>| a link time error: unresolved extern A:~A().

The ARM states that "A pure virtual function need be defined only if
explicitly called with the qualified-name syntax" (ARM 10.3, page
214).  But this is an ommission in the ARM; you also need to define it
if there are implicit calls, such in this case where the automatically
generated destructor for class B contains a call to A::~().

>>| 1) If MSVC accepts making the class A destructor "pure" and child class
>>| B does not provide a version of pure virtual function from A the MSVC
>>| compiler should generate an error when trying to instantiate an object
>>| of class B because B is an "abstract class".

No.  The ARM says that "pure virtual functions are inherited as pure
virtual functions" (ARM 10.3, page 214).  But "Destructors are not
inherited" (ARM 12.4, page 276).  So this doesn't apply to destructors.

>>| 2) MSVC Should never generate reference to A::~A() since this is a
>>| "pure" function.

No, it's clear that the destructor for B must call A::~A().

Note that it _is_ legal to give a definition for a pure virtual
function.  Under normal circumstances, this function can only
be accessed using an explicit qualifier A::pure_func().
But destructors (and some other special member functions) can also be
accessed implicitly, as you have discovered.

The behaviour is not a bug in your C++ compiler.

--
Fergus Henderson - fjh@munta.cs.mu.OZ.AU