Topic: implicit cast in delete expression?


Author: mbenkmann@gmx.de (Matthias Benkmann)
Date: Mon, 23 Jul 2001 18:50:19 GMT
Raw View
On Wed, 18 Jul 2001 16:41:48 GMT, iltchenko@yahoo.com (Andrei
Iltchenko) wrote:

>> >> #include <fstream>
>> >>
>> >> using namespace std;
>> >>
>> >> int main()
>> >> {
>> >>   istream* p=new ifstream("temp.cpp");
>> >>   istream& r=*p;
>> >>   delete r;
>> >> };
>>
>>
>> It is possible that the ifstream's operator (void*) is causing this.
>Yes!
>
>> It seems that the compiler doesn't complain when I use operator delete
>> on a void*. Is this allowed by the standard? I don't think it should
>> be. If this is indeed allowed by the standard I think it should be
>> changed. Implicit cast to void* in a delete expression makes no sense
>> at all.
>
>The Standard is very clear that the cast-expression of a
>delete-expression operator must have a pointer type, or a class type
>having a single conversion function to a pointer type. And in your
>example the latter is just the case -- 'basic_ifstream<char>' has
>exactly one conversion function with conversion-type-id being a
>pointer type, namely 'basic_ios<char>::operator void*'. In addition
>the conversion function 'basic_ios<char>::operator void*' is
>accessible from the the expression-statement 'delete r;'.
>
>As a result all of the following steps done by the compiler succeed
>for the expression 'delete r;':
>1. Name lookup,
>2. Overload resolution,
>3. Access checking.
>
>After these steps are done, the compiler is to further analize the
>construct 'delete r;' and the declarations that contribute to it. And
>it is here that the controversy happens. The Standard is plain that
>for a non-array delete-expression the value of the operand shall be a
>pointer to a non-array object, otherwise the behaviour is undefined
>(there's also a footnote #73 that says that an object cannot be
>deleted using a pointer to void, while the text on the same page
>insists that this is undefined behaviour :-). In your case, by way of
>the conversion function 'basic_ios<char>::operator void*', the operand
>is not a pointer to an object but a pointer to void. Thus the
>construct 'delete r;' is undefined behaviour.
>
>The Standard doesn't impose much on a compliant implementation when
>the latter has found a construct classified as undefined behaviour.
>The Standard doesn't even require of the implementation the generation
>of a diagnostic message, not to mention terminating the translation.

I think this should be changed. delete on void* must generate a
diagnostic, especially when the void* is the result of an implicit
cast. I would even say that it should be considered whether implicit
casts in delete expressions are desirable at all or should be
deprecated.

>See 1.3.12 and 1.4 of the Standard.
>
>So what you are faced with is a quality of implementation issue.

Well, I didn't want this conversion. I doubt anyone would. I think in
ensuring the quality of the implementation the compiler plays a major
role. Otherwise we could revert to K&R style no-prototypes functions.
Every bug caused because of them is just a quality of implementation
issue.

MSB

----
By the way:
Vacuum cleaners suck!

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: jdavison@speakeasy.org (John Michael Davison)
Date: Mon, 16 Jul 2001 22:19:28 GMT
Raw View
mbenkmann@gmx.de (Matthias Benkmann) wrote in message news:<3b51fc43.24668073@news.cis.dfn.de>...

> The following program compiles without errors or warnings on Borland
> C++ 5.5. Is this correct behaviour according to the standard? Why does
> it happen? I think that using operator delete on an istream& should
> generate a compiler error. Where is type safety here? I don't think
> any implict casts like this should be allowed in a delete expression.
>
> #include <fstream>
>
> using namespace std;
>
> int main()
> {
>   istream* p=new ifstream("temp.cpp");
>   istream& r=*p;
>   delete r;
> };

>This is not a hypothetical problem.

        The above shouldn't compile at all.  Either you mistyped the above (Did
you mean "delete &r"?), or your compiler is taking considerable liberties with
the language.

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: mbenkmann@gmx.de (Matthias Benkmann)
Date: Tue, 17 Jul 2001 22:15:20 GMT
Raw View
On Mon, 16 Jul 2001 22:19:28 GMT, jdavison@speakeasy.org (John Michael
Davison) wrote:

>mbenkmann@gmx.de (Matthias Benkmann) wrote in message news:<3b51fc43.24668073@news.cis.dfn.de>...
>
>> The following program compiles without errors or warnings on Borland
>> C++ 5.5. Is this correct behaviour according to the standard? Why does
>> it happen? I think that using operator delete on an istream& should
>> generate a compiler error. Where is type safety here? I don't think
>> any implict casts like this should be allowed in a delete expression.
>>
>> #include <fstream>
>>
>> using namespace std;
>>
>> int main()
>> {
>>   istream* p=new ifstream("temp.cpp");
>>   istream& r=*p;
>>   delete r;
>> };
>
>>This is not a hypothetical problem.
>
>        The above shouldn't compile at all.  Either you mistyped the above (Did
>you mean "delete &r"?), or your compiler is taking considerable liberties with
>the language.

I didn't mistype. As I said in my OP the error was delete MyFStream(),
where MyFStream() used to return a pointer but was changed to return a
reference. This broke the destructor but went unnoticed because the
compiler did not complain.

It is possible that the ifstream's operator (void*) is causing this.
It seems that the compiler doesn't complain when I use operator delete
on a void*. Is this allowed by the standard? I don't think it should
be. If this is indeed allowed by the standard I think it should be
changed. Implicit cast to void* in a delete expression makes no sense
at all.

MSB

----
By the way:
Vacuum cleaners suck!

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: James Dennett <jdennett@acm.org>
Date: Wed, 18 Jul 2001 01:08:46 GMT
Raw View
Matthias Benkmann wrote:
>
> On Mon, 16 Jul 2001 22:19:28 GMT, jdavison@speakeasy.org (John Michael
> Davison) wrote:
>
> >mbenkmann@gmx.de (Matthias Benkmann) wrote in message news:<3b51fc43.24668073@news.cis.dfn.de>...
> >
> >> The following program compiles without errors or warnings on Borland
> >> C++ 5.5. Is this correct behaviour according to the standard? Why does
> >> it happen? I think that using operator delete on an istream& should
> >> generate a compiler error. Where is type safety here? I don't think
> >> any implict casts like this should be allowed in a delete expression.
> >>
> >> #include <fstream>
> >>
> >> using namespace std;
> >>
> >> int main()
> >> {
> >>   istream* p=new ifstream("temp.cpp");
> >>   istream& r=*p;
> >>   delete r;
> >> };
> >
> >>This is not a hypothetical problem.
> >
> >        The above shouldn't compile at all.  Either you mistyped the above (Did
> >you mean "delete &r"?), or your compiler is taking considerable liberties with
> >the language.
>
> I didn't mistype. As I said in my OP the error was delete MyFStream(),
> where MyFStream() used to return a pointer but was changed to return a
> reference. This broke the destructor but went unnoticed because the
> compiler did not complain.
>
> It is possible that the ifstream's operator (void*) is causing this.
> It seems that the compiler doesn't complain when I use operator delete
> on a void*. Is this allowed by the standard? I don't think it should
> be. If this is indeed allowed by the standard I think it should be
> changed. Implicit cast to void* in a delete expression makes no sense
> at all.

Indeed, on compiling

#include <iostream>

int main() {
  delete std::cout;
}

My gcc says
type `class ostream' argument given to `delete', expected pointer
and does not compile the code.

Compiling the following code:
#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>

int main() {
  //  std::vector<float> FloatVec(9);
  //  std::copy(FloatVec.begin(), FloatVec.end(),
std::ostream_iterator<float> (std::cout, "\n"));

  delete std::cout;
}

gives the same error, as expected, but if I uncomment the declaration
of FloatVec and the call to std::copy, odd things happen, and gcc
prints:
warning: deleting `void*' is undefined
but compiles the code.

This looks like a bug in gcc (but I confess that this machine is
still using a pre-release version of gcc 3.0).

So, g++ doesn't even agree with itself on whether the operator void *
should be used.  What does the Standard say?

-- James Dennett

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Maciej Sobczak" <Maciej.Sobczak@cern.ch>
Date: Wed, 18 Jul 2001 15:04:14 GMT
Raw View
Hi,

Did you "rebuild all"?
It can happen that when you change something small (like pointer to
reference) but leave old object files, the compiler can get confused and
swallow everything, no matter how far from common sense it is.
It has happened to me once on M$VC++6, it can be the case for you, too.
(but if you did rebuild everything, I give up - it looks like a compiler
bug)

--
Interested in distributed, object-based programming?
Complete and consistent environment for Linux, Windows, ..., C, C++, ASP,
VB, ...
check: http://www.cern.ch/maciej/prog/yami

Maciej Sobczak, http://www.cern.ch/Maciej.Sobczak
"in theory, there is no difference between theory and practice - but in
practice, there is"



---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: iltchenko@yahoo.com (Andrei Iltchenko)
Date: Wed, 18 Jul 2001 16:41:48 GMT
Raw View
mbenkmann@gmx.de (Matthias Benkmann) wrote in message news:<3b54aa62.12040454@news.cis.dfn.de>...

> On Mon, 16 Jul 2001 22:19:28 GMT, jdavison@speakeasy.org (John Michael
> Davison) wrote:
>
> >mbenkmann@gmx.de (Matthias Benkmann) wrote in message news:<3b51fc43.24668073@news.cis.dfn.de>...
> >
> >> The following program compiles without errors or warnings on Borland
> >> C++ 5.5. Is this correct behaviour according to the standard? Why does
> >> it happen? I think that using operator delete on an istream& should
> >> generate a compiler error. Where is type safety here? I don't think
> >> any implict casts like this should be allowed in a delete expression.
> >>
> >> #include <fstream>
> >>
> >> using namespace std;
> >>
> >> int main()
> >> {
> >>   istream* p=new ifstream("temp.cpp");
> >>   istream& r=*p;
> >>   delete r;
> >> };
>
> >>This is not a hypothetical problem.
> >
> >        The above shouldn't compile at all.  Either you mistyped the above (Did
> >you mean "delete &r"?), or your compiler is taking considerable liberties with
> >the language.
>
> I didn't mistype. As I said in my OP the error was delete MyFStream(),
> where MyFStream() used to return a pointer but was changed to return a
> reference. This broke the destructor but went unnoticed because the
> compiler did not complain.
>
> It is possible that the ifstream's operator (void*) is causing this.
Yes!

> It seems that the compiler doesn't complain when I use operator delete
> on a void*. Is this allowed by the standard? I don't think it should
> be. If this is indeed allowed by the standard I think it should be
> changed. Implicit cast to void* in a delete expression makes no sense
> at all.

The Standard is very clear that the cast-expression of a
delete-expression operator must have a pointer type, or a class type
having a single conversion function to a pointer type. And in your
example the latter is just the case -- 'basic_ifstream<char>' has
exactly one conversion function with conversion-type-id being a
pointer type, namely 'basic_ios<char>::operator void*'. In addition
the conversion function 'basic_ios<char>::operator void*' is
accessible from the the expression-statement 'delete r;'.

As a result all of the following steps done by the compiler succeed
for the expression 'delete r;':
1. Name lookup,
2. Overload resolution,
3. Access checking.

After these steps are done, the compiler is to further analize the
construct 'delete r;' and the declarations that contribute to it. And
it is here that the controversy happens. The Standard is plain that
for a non-array delete-expression the value of the operand shall be a
pointer to a non-array object, otherwise the behaviour is undefined
(there's also a footnote #73 that says that an object cannot be
deleted using a pointer to void, while the text on the same page
insists that this is undefined behaviour :-). In your case, by way of
the conversion function 'basic_ios<char>::operator void*', the operand
is not a pointer to an object but a pointer to void. Thus the
construct 'delete r;' is undefined behaviour.

The Standard doesn't impose much on a compliant implementation when
the latter has found a construct classified as undefined behaviour.
The Standard doesn't even require of the implementation the generation
of a diagnostic message, not to mention terminating the translation.
See 1.3.12 and 1.4 of the Standard.

So what you are faced with is a quality of implementation issue.


> ----
> By the way:
> Vacuum cleaners suck!

What do you use instead then?


Regards,

Andrei Iltchenko.

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: mbenkmann@gmx.de (Matthias Benkmann)
Date: Mon, 16 Jul 2001 17:04:07 GMT
Raw View
The following program compiles without errors or warnings on Borland
C++ 5.5. Is this correct behaviour according to the standard? Why does
it happen? I think that using operator delete on an istream& should
generate a compiler error. Where is type safety here? I don't think
any implict casts like this should be allowed in a delete expression.

#include <fstream>

using namespace std;

int main()
{
  istream* p=new ifstream("temp.cpp");
  istream& r=*p;
  delete r;
};


This is not a hypothetical problem. I just hunted down such a bug in
my code. It was not so easy to see because the expression was

delete MyFStream()

in a destructor and I had overlooked that MyFStream() returned a
reference instead of a pointer (most probably because in an earlier
version of the class it did in fact return a pointer).
Is there any way to write a delete expression that protects me against
this happening?

MSB

----
By the way:
Vacuum cleaners suck!

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]