Topic: delete vs incomplete class type


Author: sjc@netcom.com (Steven Correll)
Date: 1996/04/01
Raw View
>Steven Correll (sjc@netcom.com) wrote:
>>         struct x;
>>         struct y;
>>
>>         void
>>         p(x *arg0, y *arg1)
>>           {
>>           delete [] arg0;
>>           delete arg1;
>>           }
>>
>> I don't see how a compiler could avoid noticing that it hasn't a clue what
>> destructor to invoke at compilation time. Is there a reason (aside from
>> encouraging people to migrate to Java) not to require the compiler to
>> diagnose this as an error, instead of allowing it to fault at execution
>> time?

In article <4jcdp0$b3p@venus.mcs.com>, Martin J. Maney <maney@mcs.com> wrote:
>So why not make this sort of thing ill-formed?  Probably so that PODS can
>continue to be used, as in legacy code that has been only partially ported
>to C++.  (I'm thinking here of code that's been cleaned up to compile as
>C++, and use some of the features such as new/delete, but that hasn't been
>redesigned as OO.  Been there, done that, and it was quite worthwhile as
>an intermediate step without which the code probaly would have had to
>remain in Plain C until it was abandoned.)...
>
>Now that you've pointed this out, I should have to agree that it would be
>very nice to see compilers diagnose this, but I wouldn't want them to
>reject such a program as ill-formed for reasons that must be obvious.
>Therefore it has to be a "quality of implementation" issue, or perhaps
>even a job for a lint++ tool, since in general one might have to examine
>files that are not normally, nor are intended to be, compiled together.

Your argument is so persuasive that I withdraw my question and ask a different
one: why the silly rule that a function must be declared before it can be
invoked? If C++ were rid of that rule, it would be much easier to port legacy
C code which has been partly converted to C++. Of course, such code will often
crash in nigh-impossible-to-debug ways, but we wouldn't want a compiler to
reject such code as ill-formed; this is a "quality of implementation" issue,
or perhaps a job for a lint++ tool which could, by examining source files that
are not normally compiled together, determine whether or not the compiler was
right when it inferred the formal argument types based on the actual argument
types.

:-)
--
Steven Correll == PO Box 66625, Scotts Valley, CA 95067 == sjc@netcom.com


[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Nathan Myers, http://www.cantrip.org/" <ncm@cantrip.org>
Date: 1996/04/02
Raw View
Steven Correll (sjc@netcom.com) wrote:
>         struct x;
>         struct y;
>
>         void
>         p(x *arg0, y *arg1)
>         {
>           delete [] arg0;
>           delete arg1;
>         }
>
> I don't see how a compiler could avoid noticing that it hasn't a clue what
> destructor to invoke at compilation time. Is there a reason ... not to
> require the compiler to diagnose this as an error, instead of allowing
> it to fault at execution time?

I have to agree with Steven ... it's silly to talk about preserving
legacy C code that has "delete" statements in it.  Given the great
difficulty in finding bugs introduced this way, and the great ease of
introducing them accidentally through inclusion errors, we certainly
should change something.

Fortunately fixing this would be a restriction, not an extension,
and thus is still conceivable in this round of standardization.

Nathan Myers
ncm@cantrip.org  http://www.cantrip.org/
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: maney@mcs.com (Martin J. Maney)
Date: 1996/04/03
Raw View
Steven Correll (sjc@netcom.com) wrote:
> Your argument is so persuasive that I withdraw my question and ask a
> different one: why the silly rule that a function must be declared
> before it can be invoked? If C++ were rid of that rule, it would be
> much easier to port legacy C code which has been partly converted to
> C++. Of course, such code will often crash in nigh-impossible-to-debug
> ways, but we wouldn't want a compiler to reject such code as
> ill-formed; this is a "quality of implementation" issue, or perhaps a
> job for a lint++ tool which could, by examining source files that are
> not normally compiled together, determine whether or not the compiler
> was right when it inferred the formal argument types based on the
> actual argument types.

> :-)

This would be more amusing if it weren't so well laced with half-plausible
misdirection, such as the amusing inversion of the role of function
declarations and lint.  I'm not sure I really want to defend the decision
about delete of an incomplete type, and I agree with Steve Clamage that
making it ill-defined is certainly the only other reasonable choice.
Having had to deal with hybrid code that might have done this very thing -
I'm not really certain, and don't have the sources around to look over any
longer - I really do think it possible that there is code in use that
might be broken by that change.

Not that I'm always wildly enthused about some of the things done for C
(and early C++) compatability, but that's as much a part of C++ as are
classes.
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: ajay@lehman.com (Ajay Kamdar)
Date: 1996/04/03
Raw View
In article <3160CA2D.646FFC15@cantrip.org>,
Nathan Myers, http://www.cantrip.org/ <ncm@cantrip.org> wrote:
>Steven Correll (sjc@netcom.com) wrote:
>>
>> I don't see how a compiler could avoid noticing that it hasn't a clue what
>> destructor to invoke at compilation time. Is there a reason ... not to
>> require the compiler to diagnose this as an error, instead of allowing
>> it to fault at execution time?
>
>I have to agree with Steven ... it's silly to talk about preserving
>legacy C code that has "delete" statements in it.  Given the great
>difficulty in finding bugs introduced this way, and the great ease of
>introducing them accidentally through inclusion errors, we certainly
>should change something.
>
>Fortunately fixing this would be a restriction, not an extension,
>and thus is still conceivable in this round of standardization.

So are you volunteering to champion a formal proposal to the
committee to add this restriction in this round of standardization?

Although it doesn't count in the committee, you do have my vote.

---
Ajay Kamdar        |    Email: ajay@lehman.com    |    Standard Disclaimer
Lehman Brothers    |    Phone: (201) 524-5048     |
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: maney@mcs.com (Martin J. Maney)
Date: 1996/03/27
Raw View
Steven Correll (sjc@netcom.com) wrote:
> What must a conforming compiler do when confronted with this?
>
>         struct x;
>         struct y;
>
>         void
>         p(x *arg0, y *arg1)
>           {
>           delete [] arg0;
>           delete arg1;
>           }
>
> Section 5.3.5 of my 5/95 copy of the draft standard says "If the object
> being deleted has incomplete class type at the point of deletion and the
> class has a non-trivial destructor...the behavior is undefined." Is this
> still true?
>
> I don't see how a compiler could avoid noticing that it hasn't a clue what
> destructor to invoke at compilation time. Is there a reason (aside from
> encouraging people to migrate to Java) not to require the compiler to
> diagnose this as an error, instead of allowing it to fault at execution

I think you have in fact answered your own question, nearly:

> time? (Given that x and y might be PODS, I doubt that it's possible to
> defer the solution to execution time, but if it is, then why not define
> the behavior and mandate that it be correct?)

I believe it is in fact that the objects might be PODS that makes this
the only reasonable rule.  For a PODS, one assumes that there is no
destructor, which is surely trivial, yes?  The problem whcih you go on to
describe is simply what happens in the general case when a user-defined
type is deleted without destruction: the destructor function isn't
invoked, and so side effects don't happen as expected.

So why not make this sort of thing ill-formed?  Probably so that PODS can
continue to be used, as in legacy code that has been only partially ported
to C++.  (I'm thinking here of code that's been cleaned up to compile as
C++, and use some of the features such as new/delete, but that hasn't been
redesigned as OO.  Been there, done that, and it was quite worthwhile as
an intermediate step without which the code probaly would have had to
remain in Plain C until it was abandoned.) This accomodates the common C
use of an opaque data structure, which one might reasonably expect to find
used in the very C code that would be a leading candidate for such a move
to C++.  Or so it seems to me.  :-)

Now that you've pointed this out, I should have to agree that it would be
very nice to see compilers diagnose this, but I wouldn't want them to
reject such a program as ill-formed for reasons that must be obvious.
Therefore it has to be a "quality of implementation" issue, or perhaps
even a job for a lint++ tool, since in general one might have to examine
files that are not normally, nor are intended to be, compiled together.



[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: clamage@Eng.sun.com (Steve Clamage)
Date: 1996/03/27
Raw View
In article 6FA@netcom.com, sjc@netcom.com (Steven Correll) writes:

>What must a conforming compiler do when confronted with this?
>
>        struct x;
>        struct y;
>
>        void
>        p(x *arg0, y *arg1)
>          {
>          delete [] arg0;
>          delete arg1;
>          }

>Section 5.3.5 of my 5/95 copy of the draft standard says "If the object
>being deleted has incomplete class type at the point of deletion and the
>class has a non-trivial destructor...the behavior is undefined." Is this
>still true?

Yes.

>I don't see how a compiler could avoid noticing that it hasn't a clue what
>destructor to invoke at compilation time. Is there a reason (aside from
>encouraging people to migrate to Java) not to require the compiler to
>diagnose this as an error, instead of allowing it to fault at execution
>time?

If x and y have trivial destructors, the code is well-formed. It would
be possible to make the code unconditionally ill-formed, meaning that
you could not delete an object unless its type is complete. I don't have
a good answer for why this is not the case. (I only see two feasible
definitions: status quo, or the code is always ill-formed.)

I would expect a compiler to warn about deleting incomplete types.
The current Sun C++ does, for example.

I don't understand the reference to Java. In Java, all objects of class
type are on the heap and are garbage-collected. This has the obvious
advantage of eliminating memory-management errors. On the other hand,
you cannot predict when (or whether, under current Java versions) an
object will ever be destroyed, so doing anything important in a
"destructor" (finalize) seems ill-advised. In effect, it seems to me
that "destructors" in Java should always be trivial, and if cleanup
actions are needed, they should usually be put in a method you call
explicitly at the appropriate time.  Hmmm -- seems isomorphic to the
C++ memory-management problem, except for having somewhat limited bad
consequences.

(OK, the comparison might not be completely fair. Typically, a C++
destructor is needed to free allocated memory, and Java never needs a
destructor for that purpose. But if the destructor is needed to free
some other resource -- close a file, release a lock -- you are back
to the "when does it happen" problem. Future versions of Java are
supposed to guarantee that the "finalize" method of every object is
eventually run, but you cannot predict or control the order in which
they are run.)

---
Steve Clamage, stephen.clamage@eng.sun.com




[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: sjc@netcom.com (Steven Correll)
Date: 1996/03/27
Raw View
What must a conforming compiler do when confronted with this?

        struct x;
        struct y;

        void
        p(x *arg0, y *arg1)
          {
          delete [] arg0;
          delete arg1;
          }

Section 5.3.5 of my 5/95 copy of the draft standard says "If the object
being deleted has incomplete class type at the point of deletion and the
class has a non-trivial destructor...the behavior is undefined." Is this
still true?

I don't see how a compiler could avoid noticing that it hasn't a clue what
destructor to invoke at compilation time. Is there a reason (aside from
encouraging people to migrate to Java) not to require the compiler to
diagnose this as an error, instead of allowing it to fault at execution
time? (Given that x and y might be PODS, I doubt that it's possible to
defer the solution to execution time, but if it is, then why not define
the behavior and mandate that it be correct?)

Forgive me for being testy, but I've spent days debugging this error in a
program generated with the Solaris 3.0.1 compiler, where the undefined "delete"
for "arg0" in the example above can cause a failure during a perfectly correct
and well-defined "delete" of a totally unrelated object (the undefined "delete"
deallocates memory but fails to remove an entry from a table in the runtime
library; if the "new" of the other object happens to reuse the same block of
memory, it puts a redundant entry into the table, and a well-defined "delete"
of that object blows up.)
--
Steven Correll == PO Box 66625, Scotts Valley, CA 95067 == sjc@netcom.com


[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]