Topic: delete considered bad style!
Author: Marcelo Cantos <marcelo@mds.rmit.edu.au>
Date: 1997/01/28 Raw View
R.W. Johnstone wrote:
>
> In article <2.2.32.19970123000736.0066ec08@central.beasys.com>,
> David R Tribble <david.tribble@central.beasys.com> wrote:
> >> |David R Tribble <david.tribble@central.beasys.com> writes:
> >> |
> >> |> const char * p = new char[len];
> >> |> ...
> >> |> delete const_cast<char *> p; // Constness cast away
> >>
> >> Doesn't 'delete p' work just as well?
>
> Just a question. Does this break autoptr?
>
> Ex. autoptr<const char> p = new char[len];
>
It certainly would, but the whole point of auto_ptr is that
you don't need to explicitly call delete. The example
didn't use an auto_ptr, therefore delete is required.
Regards,
Marcelo Cantos
---
[ 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: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/01/29 Raw View
Marcelo Cantos <marcelo@mds.rmit.edu.au> writes:
|> R.W. Johnstone wrote:
|> >
|> > In article <2.2.32.19970123000736.0066ec08@central.beasys.com>,
|> > David R Tribble <david.tribble@central.beasys.com> wrote:
|> > >> |David R Tribble <david.tribble@central.beasys.com> writes:
|> > >> |
|> > >> |> const char * p = new char[len];
|> > >> |> ...
|> > >> |> delete const_cast<char *> p; // Constness cast away
|> > >>
|> > >> Doesn't 'delete p' work just as well?
|> >
|> > Just a question. Does this break autoptr?
|> >
|> > Ex. autoptr<const char> p = new char[len];
|> >
|>
|> It certainly would, but the whole point of auto_ptr is that
|> you don't need to explicitly call delete. The example
|> didn't use an auto_ptr, therefore delete is required.
For the record:
auto_ptr< const T > p( new T ) ;
is legal. What breaks in the above example is not the const, it is the
allocation of an array (which auto_ptr will not correctly delete).
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ 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: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/01/27 Raw View
fjh@mundook.cs.mu.OZ.AU (Fergus Henderson) writes:
|> Well, apart from the problem that you've made exactly the same mistake
|> as above, that should be OK. There's nothing wrong with
|>
|> auto_ptr<const char> p = new char;
|>
|> But if you really want an array of chars, the fix is a bit harder in
|> this case, because auto_ptr only handles single objects, not arrays,
|> and there's no auto_array_ptr. The usual suggestion to use vector
|> doesn't work in this case, because vector<const char> is not valid,
|> since `const char' does not have any assignment operator.
Does vector formally require assignment, or only copy construction?
(I'll admit that without assignment, you cannot change any elements of
the vector once the element has been constructed. But you should still
be able to initialize it in an arbitrary fashion using push_back, and
read it. Or am I missing something.)
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ 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: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/01/27 Raw View
David R Tribble <david.tribble@central.beasys.com> writes:
|> I <david.tribble@central.beasys.com> wrote:
|> > If you've got pointer 'p' inside an object of class Foo and another
|> > pointer 'q' in class Bar is pointing to 'p' (a double indirection),
|> > it surely is *not* a waste of time setting 'p' to NULL after it's
|> > deleted, whether you use '*q' or not, because it's a dangling pointer.
|>
|> Greg Comeau <comeau@panix.com> responded:
|> > Folks often becomes too ptr centric on this issue, but in fact,
|> > lots of code ends up with dandling data, ptrs or otherwise.
|> > And as admirable as setting them to a non-dangling value might be,
|> > it does not by itself, nor in every context, solve the issue.
|>
|> This will sound like boasting, but my code doesn't. I 'delete' every
|> 'new' and set every deleted pointer to NULL. I have to - some of my code
|> runs in server programs that run as long as the machine is up (7x24
|> operation).
Your code doesn't what? Greg said that the proposed solution doesn't
solve all of the problems. It is, in fact, easy to prove that he is
right; one example suffices (and several have been posted).
Obviously, setting every deleted pointer to NULL is not going to cause
memory leaks. But if your programs do run indefinitly without problems,
then you obviously do more than just setting every deleted pointer to
NULL to ensure this. (You probably, for example, have done some design
work before writing code.)
|> I also wrote:
|> >> Initialize every member of a class when it's constructed.
|>
|> Greg Comeau responded:
|> > At least try to. But sometimes mandating it to be done is just as bad.
|>
|> Perhaps someone can provide an example of when it's desirable to leave
|> a member of an object uninitialized? I've never encountered such a
|> situation.
An obvious case: the member is an array:-).
In practice, it probably depends on your constraints. In many graphical
applications, for example, performance is critical, and you can afford
the risk. (No one dies if it fails.) I agree that the case is pretty
exceptional and, IMHO, generally limited to low-level classes
(implementing STL, etc.).
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ 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: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/01/27 Raw View
James Kanze <james-albert.kanze@vx.cit.alcatel.fr> writes:
>fjh@mundook.cs.mu.OZ.AU (Fergus Henderson) writes:
>
>|> ... vector<const char> is not valid,
>|> since `const char' does not have any assignment operator.
>
>Does vector formally require assignment, or only copy construction?
Yes, vector formally requires assignment.
| 23.1 Container requirements [lib.container.requirements]
[...]
| 3 The type of objects stored in these components must meet the require-
| ments of CopyConstructible types (_lib.copyconstructible_), and the
| additional requirements of Assignable types.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ 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: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/01/27 Raw View
Per Angstrom <qdtpang@toedts3.ericsson.se> writes:
|> James Kanze wrote:
|>
|> > Concerning setting the pointer to null after delete: 99% of
|> > my delete's are either in a destructor, or are followed by
|> > an assignment to the pointer in the next line (basically:
|> > a realloc). This is by design, so I hardly see what setting
|> > the pointer to null will buy me.
|>
|> I don't want to contradict you, James, but I would like
|> to point out that there are cases when setting a deleted
|> pointer to null is the easiest way to write exception-safe
|> code.
[...]
|> void
|> A::reinit( int i )
|> {
|> delete pB;
|> // pB now points to deleted memory
|> pB = NULL; // exception-safe
|> pB = new B( i );
|> }
Generally, I'd write this:
void
A::reinit( int i )
{
B* newPB( new B( i ) ) ;
delete pB ;
pB = newPB ;
}
In the case of a single element, I'd only use a pointer if it were
polymorphic, in which case, it would be a reference counted pointer, and
the case would take care of itself (since the delete would not take
place until I had successfully allocated the new object).
As I said in the parentheses, I use this idiom to implement something
similar to realloc. In this case, however, I need the old contents, in
order to correctly initialize the new. So the delete cannot take place
until the new has successfully completed. (In practice, in such cases,
I almost always separate allocation and construction, as is done in the
STL classes. This does mean that exception safety requires some
attention. IMHO, this is acceptable, because I only do it in a few,
widely used basic classes; application software NEVER new's an array,
but uses classes like vector, so the problem cannot occur.)
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ 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: David R Tribble <david.tribble@central.beasys.com>
Date: 1997/01/23 Raw View
> |David R Tribble <david.tribble@central.beasys.com> writes:
> |
> |> const char * p = new char[len];
> |> ...
> |> delete const_cast<char *> p; // Constness cast away
>
> Doesn't 'delete p' work just as well?
Nope. The compiler complains (usual with only a warning, not an error) that
the const-ness of 'p' has been wiped away, or that you can't delete a const
object (which technically modifies the object, after all).
This is an example of a situation that can't be defined in C++: I want to
have a private string (a char pointer) in my object that I want to allocate
once, fill it with a value, then treat it like a 'const char *' throughout
the lifetime of the object. Eventually (such as when the object is
destructed), I want to free (delete) the string. This requires an explicit
cast to remove the 'const' on the pointer during the delete.
-- David R. Tribble, david.tribble@central.beasys.com --
---
[ 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: comeau@panix.com (Greg Comeau)
Date: 1997/01/23 Raw View
In article <2.2.32.19970123000736.0066ec08@central.beasys.com> David R Tribble <david.tribble@central.beasys.com> writes:
>> |David R Tribble <david.tribble@central.beasys.com> writes:
>> |
>> |> const char * p = new char[len];
>> |> ...
>> |> delete const_cast<char *> p; // Constness cast away
>>
>> Doesn't 'delete p' work just as well?
>
>Nope. The compiler complains (usual with only a warning, not an error) that
>the const-ness of 'p' has been wiped away, or that you can't delete a const
>object (which technically modifies the object, after all).
A delete [] p; _is_ allowed. This is a semi-recent change and so the
warning as a transition model perhaps makes sense.
>This is an example of a situation that can't be defined in C++: I want to
>have a private string (a char pointer) in my object that I want to allocate
>once, fill it with a value, then treat it like a 'const char *' throughout
>the lifetime of the object. Eventually (such as when the object is
>destructed), I want to free (delete) the string. This requires an explicit
>cast to remove the 'const' on the pointer during the delete.
Cannot be defined?? I don't follow. Anyway, see above.
- Greg
--
Comeau Computing, 91-34 120th Street, Richmond Hill, NY, 11418-3214
Producers of Comeau C++ 4.0 front-end pre-release
****WEB: http://www.comeaucomputing.com / Voice:718-945-0009 / Fax:718-441-2310
Here:comeau@comeaucomputing.com / BIX:comeau or comeau@bix.com / CIS:72331,3421
[ 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: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/01/24 Raw View
comeau@panix.com (Greg Comeau) writes:
[Concerning setting a pointer to null on deletion...]
|> Also, while we are at it, what about functions such as fclose()?
Doesn't everybody set the FILE* to NULL after fclose:-)? (For those who
don't understand smileys: I've never seen anyone, including myself, who
did.)
Concerning setting the pointer to null after delete: 99% of my delete's
are either in a destructor, or are followed by an assignment to the
pointer in the next line (basically: a realloc). This is by design, so
I hardly see what setting the pointer to null will buy me.
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ 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: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/01/24 Raw View
Marcelo Cantos <marcelo@mds.rmit.edu.au> writes:
|> Hoshi Takanori wrote:
|> >
|> > In article <2.2.32.19970115165622.002c5f48@central.beasys.com>
|> > David R Tribble <david.tribble@central.beasys.com> writes:
|> >
|> > > const char * p = new char[len];
|> > > ...
|> > > delete const_cast<char *> p; // Constness cast away
|>
|> Doesn't 'delete p' work just as well?
Or just as poorly:-)? According to the current draft, "delete [] p"
should be fine. Earlier drafts, however, required the pointer in the
delete expression to be non-const, and many compilers still implement it
this way.
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ 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: David R Tribble <david.tribble@central.beasys.com>
Date: 1997/01/24 Raw View
I <david.tribble@central.beasys.com> wrote:
> If you've got pointer 'p' inside an object of class Foo and
> another pointer 'q' in class Bar is pointing to 'p' (a double indirection),
> it surely is *not* a waste of time setting 'p' to NULL after it's deleted,
> whether you use '*q' or not, because it's a dangling pointer.
Greg Comeau <comeau@panix.com> responded:
> Folks often becomes too ptr centric on this issue, but in fact,
> lots of code ends up with dandling data, ptrs or otherwise.
> And as admirable as setting them to a non-dangling value might be,
> it does not by itself, nor in every context, solve the issue.
This will sound like boasting, but my code doesn't. I 'delete' every 'new'
and set every deleted pointer to NULL. I have to - some of my code runs
in server programs that run as long as the machine is up (7x24 operation).
---
I also wrote:
>> Initialize every member of a class when it's constructed.
Greg Comeau responded:
> At least try to. But sometimes mandating it to be done is just as bad.
Perhaps someone can provide an example of when it's desirable to leave
a member of an object uninitialized? I've never encountered such a
situation.
-- David R. Tribble, david.tribble@central.beasys.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: Per Angstrom <qdtpang@toedts3.ericsson.se>
Date: 1997/01/24 Raw View
James Kanze wrote:
> Concerning setting the pointer to null after delete: 99% of
> my delete's are either in a destructor, or are followed by
> an assignment to the pointer in the next line (basically:
> a realloc). This is by design, so I hardly see what setting
> the pointer to null will buy me.
I don't want to contradict you, James, but I would like
to point out that there are cases when setting a deleted
pointer to null is the easiest way to write exception-safe
code.
It is not strictly necessary when you are dealing with
pointers on the stack, or when you simply don't catch
(or throw) any exceptions. But consider the following
program, which would lead to undefined behaviour unless
I set the deleted pointer to null.
#include <stdlib.h>
#include <iostream.h>
class bad_arg {};
struct B {
B( int i ) { if ( i == 666 ) throw bad_arg(); }
};
struct A {
A( int i );
~A();
void reinit( int i );
B * pB;
};
A::A( int i )
: pB( new B( i ) )
{
}
void
A::reinit( int i )
{
delete pB;
// pB now points to deleted memory
pB = NULL; // exception-safe
pB = new B( i );
}
A::~A()
{
// pB is either NULL or a valid pointer.
cout << "pB: " << pB << endl;
delete pB;
}
void func()
{
A a( 2 );
A a2( 2 ); // for demonstration purposes
a.reinit( 666 );
}
int main()
{
try {
func();
}
catch ( bad_arg & ) {
cerr << "fatal error" << endl;
exit( EXIT_FAILURE );
}
}
// end program
I think you'll agree that this solution is easier than the
alternatives, such as enclosing each new in a try block.
------
Per Angstrom (qdtpang@toedt.ericsson.se)
---
[ 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: johnstrw@muss.CIS.McMaster.CA (R.W. Johnstone)
Date: 1997/01/25 Raw View
In article <2.2.32.19970123000736.0066ec08@central.beasys.com>,
David R Tribble <david.tribble@central.beasys.com> wrote:
>> |David R Tribble <david.tribble@central.beasys.com> writes:
>> |
>> |> const char * p = new char[len];
>> |> ...
>> |> delete const_cast<char *> p; // Constness cast away
>>
>> Doesn't 'delete p' work just as well?
Just a question. Does this break autoptr?
Ex. autoptr<const char> p = new char[len];
Excuse me if I make a mistake, I don't have access to a (almost) standard
compiler.
---
[ 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: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/01/25 Raw View
R.W. Johnstone wrote:
>
> In article <2.2.32.19970123000736.0066ec08@central.beasys.com>,
> David R Tribble <david.tribble@central.beasys.com> wrote:
> >> |David R Tribble <david.tribble@central.beasys.com> writes:
> >> |
> >> |> const char * p = new char[len];
> >> |> ...
> >> |> delete const_cast<char *> p; // Constness cast away
> >>
> >> Doesn't 'delete p' work just as well?
>
> Just a question. Does this break autoptr?
>
> Ex. autoptr<const char> p = new char[len];
>
> Excuse me if I make a mistake, I don't have access to a (almost) standard
> compiler.
That's a FAQ.
auto_ptr (not autoptr) deallocates objects allocated with new by
calling delete so your example invoke undefined behaviour (in
practice is can trash the heap).
--
Valentin Bonnard
mailto:bonnardv@pratique.fr
http://www.pratique.fr/~bonnardv (Informations sur le C++ en Francais)
[ 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: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/01/25 Raw View
johnstrw@muss.CIS.McMaster.CA (R.W. Johnstone) writes:
>In article <2.2.32.19970123000736.0066ec08@central.beasys.com>,
>David R Tribble <david.tribble@central.beasys.com> wrote:
>>> |David R Tribble <david.tribble@central.beasys.com> writes:
>>> |
>>> |> const char * p = new char[len];
>>> |> ...
>>> |> delete const_cast<char *> p; // Constness cast away
>>>
>>> Doesn't 'delete p' work just as well?
As someone pointed out already, neither of these work,
since it should be `delete []' in both cases. But apart
from that, yes, `delete [] p' works just as well as
`delete [] const_cast<char *>(p)'.
>Just a question. Does this break autoptr?
>
>Ex. autoptr<const char> p = new char[len];
Well, apart from the problem that you've made exactly the same mistake
as above, that should be OK. There's nothing wrong with
auto_ptr<const char> p = new char;
But if you really want an array of chars, the fix is a bit harder in
this case, because auto_ptr only handles single objects, not arrays,
and there's no auto_array_ptr. The usual suggestion to use vector
doesn't work in this case, because vector<const char> is not valid,
since `const char' does not have any assignment operator.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ 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: hoshi@sra.co.jp (Hoshi Takanori)
Date: 1997/01/20 Raw View
In article <2.2.32.19970115165622.002c5f48@central.beasys.com> David R Tribble <david.tribble@central.beasys.com> writes:
> const char * p = new char[len];
> ...
> delete const_cast<char *> p; // Constness cast away
You should use `delete[]', instead of plain `delete', for
objects allocated with new[]. Or has the standard changed?
By the way, I hope the standard has `auto_array<>' template
which uses `delete[]' instead of `delete'.
hoshi
---
[ 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: Marcelo Cantos <marcelo@mds.rmit.edu.au>
Date: 1997/01/22 Raw View
Hoshi Takanori wrote:
>
> In article <2.2.32.19970115165622.002c5f48@central.beasys.com>
> David R Tribble <david.tribble@central.beasys.com> writes:
>
> > const char * p = new char[len];
> > ...
> > delete const_cast<char *> p; // Constness cast away
Doesn't 'delete p' work just as well?
Marcelo Cantos
__________________________________________________
Multimedia Database Systems Group, RMIT, Australia
---
[ 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: comeau@panix.com (Greg Comeau)
Date: 1997/01/22 Raw View
In article <2.2.32.19970115165622.002c5f48@central.beasys.com>
David R Tribble <david.tribble@central.beasys.com> writes:
>>Finally, there's a simple efficiency argument. If you never reference a
>>pointer variable after deleting it, it's a waste of time setting it to
>>NULL.
>
>Depends. If you've got pointer 'p' inside an object of class Foo and another
>pointer 'q' in class Bar is pointing to 'p' (a double indirection), it surely
>is *not* a waste of time setting 'p' to NULL after it's deleted, whether you
>use '*q' or not, because it's a dangling pointer.
Folks often becomes too ptr centric on this issue, but in fact,
lots of code ends up with dandling data, ptrs or otherwise.
And as admirable as setting them to a non-dangling value might be,
it does not by itself, nor in every context, solve the issue.
>Also, setting a pointer to NULL after it's deleted fills that word of memory
>with an invalid pointer value. If that word of memory is reallocated as
>storage for another object (which is very likely), it starts out life as a
>fairly safe value in the new object. This is especially useful if
>programmers are lax about initializing all the members of a class in their
>constructors. (It's a flaw of C++ that it doesn't initialize all non-class
>type members (ints, enums, floats, and pointers) to zero by default anyway).
>This prompts me to state another good rule to follow:
This argument is flawed for a number of reasons:
(1) It is a false sense of security that it will start out its life safe.
That's one of the inherent dangers, not safety, of having added such
a feature to delete.
(2) I think you agree with this at least in part because you argue this out
about init'ing in ctors -- it should be elsewhere.
(3) Still I disagree with that (at least as a blanket statement).
To wit: it DOES NOT make sense to init all non-class members to zero
(of the appropriate type).
> Initialize every member of a class when it's constructed.
At least try to. But sometimes mandating it to be done is just as bad.
>Setting a pointer to NULL after it's deleted follows the complementary rule:
>
> Set every variable to a 'safe' value when it's no longer needed,
> especially pointers.
But some don't have safe values, that's part of my point.
>Coding this way is known generally as "defensive programming", i.e., doing
>extra things to protect yourself from disaster occurring as a result of
>badly written code (which may not be yours) that executes later in the
>program.
>
>I'll state the original rule again, for emphasis:
>
> A pointer should *always* be set to NULL immediately after it's deleted
> (i.e., after the object it points to is deleted). Otherwise, it's in
> an undefined state (by definition, since the compiler is free to modify
> it during the delete operation).
>
>If you think this is inefficient because you know you'll never reference that
>pointer again, you've just allowed a lurking bug to exist. How sure can you
>be? What about when the program is altered months later? If you think that
>extra CPU instruction is a waste of time, consider that the compiler could
>optimize it out if it thinks there are no more further references to the
>pointer.
This defensive logic seems reasonable and in general is probably what we
should all be striving for. However, setting the delete'd pointer
to a null pointer is not as rosy as it is being presented, because
the information is incomplete in some ways. In brief:
Pros of delete setting the ptr to the null pointer being made:
(1) It's automatic
(2) Can write a template for it to work with different types
(including arrays)
(3) If it catches just one violation it's worth it
(4) Will be set "next time around" already
(But this is wrong for a number of reasons).
(5) Helps if the ptr is delete'd more than once.
(but this is actually a con, because it can be argued that
this code is wrong).
(6) Consistent
Cons:
(1) Might be too expensive for array's?
(2) Passing an invalid pointer or other invalid arguments will do even
more damamge
(3) It's a false sense of security
(4) The template will need a header file
(5) We need two templates: one for array, one for non-array
(6) You "forget" to use the template
(7) Pro[4] really be done in the new? ctor? Etc.
(8) Initializing something to zero (of the appropriate type)
is often not good enough.
(9) The argument to delete is not always modifiable
(might be const, might not be an lvalue, etc)
(10) What would delete new T; yield? (at least semantically)
(11) Previous _copies_ of the pointer do not get null'd.
(Note that some copying is not obvious, even if just passing
the pointer to function!)
(12) Your code knows it has deleted something, and where,
shouldn't it have some say?
(13) The compiler may not be able to "fix" all the cases
(better than nothing, but again, false sense of security)
(14) This relies strictly on program checks and not (instead/additionally)
program logic, flow or structure. But all are important.
So is contemplating "pointer ownership."
(15) delete doesn't do this now, and if one is added that it now does
do it, I think a major source of new bugs opens up, not closes.
(16) Some argue for no pointers in user code, other for mechanisms
such as auto_ptr (some arguments going hand in hand with EH),
instead as possible alternatives in some cases.
This, and (14), seems to be where the opportunity for robustness,
safety, etc, can more likely come from. That is, use some other
automatic routines, that in fact will be even more automatic.
In summary, at first glance this seems a good thing.
However, once past a cursory look, the win is not so clear.
Also, while we are at it, what about functions such as fclose()?
At some level this too is analogous to whether free() and delete
should return a value. I think it it is also analogous to saying
that if a function detects an error, it should abort right then and
there. These need not be the case. Nor does this.
I'm all for consistency and known semantics, but I'm also for
that it's not as simple as that, and also that issues of robustness
and such as do have have single lane paths to their resolution.
- Greg
--
Comeau Computing, 91-34 120th Street, Richmond Hill, NY, 11418-3214
Producers of Comeau C++ 4.0 front-end pre-release
****WEB: http://www.comeaucomputing.com / Voice:718-945-0009 /Fax:718-441-2310
Here:comeau@comeaucomputing.com /BIX:comeau or comeau@bix.com /CIS:72331,3421
---
[ 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: Olaf Weber <Olaf.Weber@cwi.nl>
Date: 1997/01/17 Raw View
Marek MAKOWSKI writes:
> However, you examples are rather "exotic", in a vast majority of
> cases setting a deleted pointer to 0 would save a lot of time and
> aggrevation.
IMHO these pleas for autmagically setting a deleted pointer to NULL do
miss a point: code that calls delete twice on the same pointer is
_buggy_, and if delete sets the pointer to NULL that bug will remain
undetected. (After all, delete NULL is a no-op.) As Marek notes:
> ... the simple rule of thumb says that each new should have a
> corresponding delete. ...
But what he favors will hamper the effort to find voliations of that
rule. (Such violations would probably indicate some screw-up in the
logic of the program.)
> Finally, I know that auto pointers make that problem "less serious".
Not just that, in the presence of exceptions auto pointers or their
ilk are a necessity anyway: you don't have that much choice if you
want your code to be reliable.
--
Olaf Weber
---
[ 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: "Bill Wade" <bill.wade@stoner.com>
Date: 1997/01/17 Raw View
Barry Margolin <barmar@bbnplanet.com> wrote in article
<5bi165$hvo@poblano.near.net>...
> In article <5bh1c7$mmm@kane.ico.net>,
> Matt Seitz <mseitz@meridian-data.com> wrote:
> >That makes sense to me, but I have to wonder: if one should always set
a
> >pointer to NULL following a delete, then why doesn't delete just
automatically
> >set the pointer to NULL?
It's also not always true you want to set the pointer to NULL. Sometimes
you want to set it to something else. Here is a slightly contrived
example:
class gizmo
{
// Keep a double-linked list of all gizmos for assorted reasons.
gizmo* prev;
gizmo* next;
static gizmo* list;
// All constructors/destructors are private, so that all gizmo's are on
// heap.
gizmo():next(list),prev(0)
{
if(next) next->prev = this;
list = this;
}
~gizmo()
{
if(prev) prev->next = next;
else list = next;
if(next) next->prev = prev;
}
...
public:
static gizmo* Create(){ return new gizmo; }
static void DeleteAll(){ while(list) delete list; }
...
};
Classes which are active participants in a larger container (lists, trees,
etc.) may want to "fix" the pointer which deleted them. This might involve
setting the pointer to NULL, or to some other value, as shown above in the
interaction between DeleteAll and ~gizmo.
---
[ 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: comeau@panix.com (Greg Comeau)
Date: 1997/01/18 Raw View
In article <uenfliwan.fsf@kastle.com> Richard Krehbiel <rich@kastle.com>
writes:
>David R Tribble <david.tribble@central.beasys.com> writes:
>
>> >>That makes sense to me, but I have to wonder: if one should always set a
>> >>pointer to NULL following a delete, then why doesn't delete just
>> >>automatically set the pointer to NULL?
>>
>> Good question. You aren't the first person to suggest this, and I agree
>> with the idea.
>
>I agree with the sentiment. I don't agree with the solution. I'd
>rather delete behave uniformly, and not have a side effect that is
>sometimes carried out and sometimes not.
The problem with the question is that the premise is too strong.
That is to say, who says one should always set a pointer to NULL
following a delete? Hence, then, why should the standard say it should?
>> >Furthermore, there's no requirement that the argument to delete be a
>> >modifiable lvalue.
>>
>> True. But then again, the compiler knows it's not an lvalue. It could
>> also detect the following case, and still (properly) set the pointer to
>> NULL:
>>
>> const char * p = new char[len];
>> ...
>> delete const_cast<char *> p; // Constness cast away
>
>But delete may be given a real true-to-life rvalue.
>
> char *remotefunc();
> delete remotefunc();
>
>Also note that a #define like the following will give you what you're
>asking for:
>
>#define DISPOSE(x) do { delete x; x = NULL; } while(0)
>
>Just watch out for side effects in x, which is evaluated twice. (I'm
>not good at templates; I suspect a template could do the same thing
>without the side effect problem.)
>
A template might look like:
template <class T>
inline void mydelete(T*& ptr) { delete ptr; ptr = 0; }
>> >Finally, there's a simple efficiency argument. If you never reference a
>> >pointer variable after deleting it, it's a waste of time setting it to
>> >NULL.
>
>Using the above macro, if x is an automatic variable, then the
>compiler will likely optimize away the assignment; it can see that the
>next thing that happens to it is going out of scope.
Equally, so can the programmer (in this case).
So a counter argument is that perhaps program structure should
have something to do with this in some cases and not blanket
requirement on an operation?
- Greg
--
Comeau Computing, 91-34 120th Street, Richmond Hill, NY, 11418-3214
Producers of Comeau C++ 4.0 front-end pre-release
****WEB: http://www.comeaucomputing.com / Voice:718-945-0009 /Fax:718-441-2310
Here:comeau@comeaucomputing.com / BIX:comeau or comeau@bix.com /CIS:72331,3421
---
[ 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: comeau@panix.com (Greg Comeau)
Date: 1997/01/18 Raw View
In article <822855055wnr@ma.ccngroup.com> aGriffiths@ma.ccngroup.com writes:
>In article: <2.2.32.19970114174340.002de65c@central.beasys.com> David R Tribble <david.tribble@central.beasys.com> writes:
>>
>> > int* p = new int;
>> > ...
>> > delete p;
>> > delete p;
>>
>> This is bad "style" because it doesn't follow the rules, which leads
>> to undefined behavior. Once an object has been deleted via a
>> pointer, that pointer is in an undefined state. The compiler is free
>> to modify the pointer (!) during the deletion operation. Also, it's
>> obvious that the pointer is no longer valid (a dangling pointer)
>> after the delete, since it's not pointing to any valid object. The
>> second delete statement exposes the danger of this undefined state of
>> 'p'. If 'p' is anything other than NULL, the second delete will also
>> result in undefined (and probably catastrophic) behavior.
>>
>> Therefore, the correct "style" is to set 'p' to NULL immediately
>> after it's been deleted. This preserves the semantics of the deletion
>> operation, and puts the pointer into a known, stable state.
>> Any subsequent deletes of 'p' will then operate benignly.
>>
>> This is a coding "style" that should be followed without question
>> after every delete statement (even if the pointer variable is about to
>> go out of scope), but too few programmers are diligent enough to do
>> that. That's the sort of sloppy coding that leads to memory leaks,
>> double deletions, and dangling pointers.
>
This may be a sound argument for this sole example, however,
I'm sure that for every scenario such as this, there is one to
match it where setting the ptr to the null ptr will have as
catastrophic a result. So. in a real way, this argument doesn't
help the situation.
>Actually, having "delete" explicitly in client code is bad style, it
>should only occur in the destructor or assignment operator of smart
>pointer templates (or other objects whose sole purpose is to manage
>a memory resource). Anything else become unmanagable in the presence
>of exceptions.
This tends to be disappointing in light of the possibilities above,
but reality sorta doesn't lend to it in any other way, so yes, this is
indeed an additional path that should be considered.
- Greg
--
Comeau Computing, 91-34 120th Street, Richmond Hill, NY, 11418-3214
Producers of Comeau C++ 4.0 front-end pre-release
****WEB: http://www.comeaucomputing.com / Voice:718-945-0009 / Fax:718-441-2310
Here:comeau@comeaucomputing.com / BIX:comeau or comeau@bix.com / CIS:72331,3421
---
[ 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: Ian Haggard <ian@shellus.com>
Date: 1997/01/18 Raw View
In article <1997Jan16.094628.10875@iiasa.ac.at>,
marek@iiasa.ac.at (Marek MAKOWSKI) wrote:
>
> Barry Margolin (barmar@bbnplanet.com) wrote:
> : In article <5bh1c7$mmm@kane.ico.net>,
> : Matt Seitz <mseitz@meridian-data.com> wrote:
> : >That makes sense to me, but I have to wonder: if one should always set
> : >a pointer to NULL following a delete, then why doesn't delete just
> : >automatically set the pointer to NULL?
>
> I think that Matt made a good point and your arguments are not convincing.
> Formally you are right, it would be difficult (and not rational) to trace
> back all uses of a pointer to be deleted.
> However, you examples are rather "exotic", in a vast majority of cases
> setting a deleted pointer to 0 would save a lot of time and aggrevation.
I'd have to side with Barry here. What you want to do simply is
impossible to do correctly without garbage-collection. And
garbage-collection is not possible unless the types of casts a user can
do are seriously restricted in the language. I personally wouldn't mind
dropping C-style casts, as well as static_cast and reinterpret_cast from
the language or further restricting the kinds of casts they can perform
in exchange for garbage-collection. But you'd have a lot of other
people who would be very angry with you.
Moreover, the only thing that having delete set its argument to null
accomplishes is that it hides the logic error that caused you to try do
delete the same value twice.
Plus, it breaks code that looks like this:
set<Foo*> fooSet;
Foo* foo=new Foo;
fooSet.push_back(foo);
delete foo;
fooSet.erase(foo);
I don't believe this code is any more supported by the standard than is
deleting the same thing twice (April Working Paper sec. 3.7.3.2.5). But
there are probably real people out there with code like this. And this
code actually is meaningful and understandable. Even though its meaning
is not sanctioned by the standard, I can't think of a single
implementation on which it doesn't work.
But this whole sub-thread is missing the real point -- users should not
have to perform deallocation themselves. The implementations of smart
pointers and container classes (which viewed in the context of this
discussion are just special ways of grouping smart pointers together)
should be the only parts of a program that use delete. Any other use of
delete is much more error-prone, as this sub-thread demonstrates. And
with the advent of exceptions, any other use of delete becomes all but
unmaintainable.
And any other use is also probably the result of the programmer's lack
of understanding as to what's really going on in their code -- if they
understood what was really going on in their code, then they would in
all probability be able to replace their raw pointers with some sort of
smart pointers, be they reference-counting smart pointers or
garbage-collecting smart pointers.
--
Ian Haggard || ian@shellus.com (work) || IanHaggard@juno.com (home)
Linux -- "Oh, no, Mr Bill!" || #define employer_opinion !my_opinion
---
[ 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: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/01/20 Raw View
Ian Haggard <ian@shellus.com> writes:
|> In article <1997Jan16.094628.10875@iiasa.ac.at>,
|> marek@iiasa.ac.at (Marek MAKOWSKI) wrote:
|> >
|> > Barry Margolin (barmar@bbnplanet.com) wrote:
|> > : In article <5bh1c7$mmm@kane.ico.net>,
|> > : Matt Seitz <mseitz@meridian-data.com> wrote:
|> > : >That makes sense to me, but I have to wonder: if one should always se
t
|> > : >a pointer to NULL following a delete, then why doesn't delete just
|> > : >automatically set the pointer to NULL?
|> >
|> > I think that Matt made a good point and your arguments are not convincing
.
|> > Formally you are right, it would be difficult (and not rational) to trace
|> > back all uses of a pointer to be deleted.
|> > However, you examples are rather "exotic", in a vast majority of cases
|> > setting a deleted pointer to 0 would save a lot of time and aggrevation.
|>
|> I'd have to side with Barry here. What you want to do simply is
|> impossible to do correctly without garbage-collection. And
|> garbage-collection is not possible unless the types of casts a user can
|> do are seriously restricted in the language. I personally wouldn't mind
|> dropping C-style casts, as well as static_cast and reinterpret_cast from
|> the language or further restricting the kinds of casts they can perform
|> in exchange for garbage-collection. But you'd have a lot of other
|> people who would be very angry with you.
Several points:
1. In your restriction concerning static_cast's, I presume that you only
meant static_cast's involving pointers. Or do you also want to ban
casts between floats and ints?
2. Casts, including static_cast's and reinterpret_cast's, do not, in
themselves, cause problems with garbage collection. The fact that you
can memcpy a pointer into an array of char's, and memcpy it out later,
does, as does the fact that you can write it to disk, and read it back
in later.
3. Modulo a few simple restrictions (precisely concerning things like
writing to disk, etc.), there is a garbage collection implementation
that works with C++. I had even heard that it might be incorporated in
some future version of g++, but that was some time ago.
|> Moreover, the only thing that having delete set its argument to null
|> accomplishes is that it hides the logic error that caused you to try do
|> delete the same value twice.
|>
|> Plus, it breaks code that looks like this:
|> set<Foo*> fooSet;
|> Foo* foo=new Foo;
|> fooSet.push_back(foo);
|> delete foo;
|> fooSet.erase(foo);
|> I don't believe this code is any more supported by the standard than is
|> deleting the same thing twice (April Working Paper sec. 3.7.3.2.5). But
|> there are probably real people out there with code like this. And this
|> code actually is meaningful and understandable. Even though its meaning
|> is not sanctioned by the standard, I can't think of a single
|> implementation on which it doesn't work.
This is definitly undefined behavior, and I've actually worked with
implementations where it wouldn't work. It's also worth noting that
Purify will flag it as an error.
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ 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: barmar@bbnplanet.com (Barry Margolin)
Date: 1997/01/15 Raw View
In article <5bh1c7$mmm@kane.ico.net>,
Matt Seitz <mseitz@meridian-data.com> wrote:
>That makes sense to me, but I have to wonder: if one should always set a
>pointer to NULL following a delete, then why doesn't delete just automatically
>set the pointer to NULL?
Because the compiler can't easily find all the pointers that need to be
nulled. E.g.
p1 = p2;
delete p1;
At this point you should set both p1 and p2 to NULL. The system could
easily set p1 to NULL, but it would have a hard time knowing that it should
also set p2.
Furthermore, there's no requirement that the argument to delete be a
modifiable lvalue. E.g. the following are valid:
p1++;
delete (p1 - 1);
Finally, there's a simple efficiency argument. If you never reference a
pointer variable after deleting it, it's a waste of time setting it to
NULL. It's possible that the compiler could perform flow analysis and
determine this and leave out the NULL assignment, but in many cases this is
not statically determinable.
--
Barry Margolin
BBN Planet, Cambridge, MA
barmar@bbnplanet.com - Phone (617) 873-3126 - Fax (617) 873-5508
(BBN customers, please call (800) 632-7638 option 1 for support)
[ 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: herbs@cntc.com (Herb Sutter)
Date: 1997/01/15 Raw View
On 15 Jan 1997 02:20:56 GMT, mseitz@meridian-data.com (Matt Seitz)
wrote:
>>Therefore, the correct "style" is to set 'p' to NULL immediately
>>after it's been deleted.
>>This is a coding "style" that should be followed without question
>>after every delete statement
This suggestion comes up periodically and there's nothing wrong with
it, but it doesn't really solve the problem you might think it solves
because of pointer aliasing. See also the current thread on this
topic in comp.lang.c++.moderated (I think the subject is still "delete
this;").
>That makes sense to me, but I have to wonder: if one should always set a
>pointer to NULL following a delete, then why doesn't delete just automatically
>set the pointer to NULL?
As above. The compiler is indeed free to change the pointer to
anything it likes... in fact, more useful than a null is a "known bad"
pointer, such as the 0xbaadf00d (try pronouncing it!) popular on some
32-bit platforms. That way the run-time system can distinguish an
"attempt to access deleted object" (at least through the original
pointer, if not through aliases) from a plain-vanilla core dump.
---
Herb Sutter (herbs@cntc.com)
Current Network Technologies Corp.
3100 Ridgeway, Suite 42, Mississauga ON Canada L5L 5M5
Tel 416-805-9088 Fax 905-608-2611
---
[ 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: David R Tribble <david.tribble@central.beasys.com>
Date: 1997/01/15 Raw View
>>That makes sense to me, but I have to wonder: if one should always set a
>>pointer to NULL following a delete, then why doesn't delete just
>>automatically set the pointer to NULL?
Good question. You aren't the first person to suggest this, and I agree with
the idea.
>Because the compiler can't easily find all the pointers that need to be
>nulled.
That doesn't matter. The compiler should only set the operand of the delete
to NULL. It's up to the programmer to take care of all the other pointers
to the same object (since C++ does not do garbage collection). This is true
when programming in any language that doesn't do garbage collection.
>Furthermore, there's no requirement that the argument to delete be a
>modifiable lvalue.
True. But then again, the compiler knows it's not an lvalue. It could also
detect the following case, and still (properly) set the pointer to NULL:
const char * p = new char[len];
...
delete const_cast<char *> p; // Constness cast away
>Finally, there's a simple efficiency argument. If you never reference a
>pointer variable after deleting it, it's a waste of time setting it to
>NULL.
Depends. If you've got pointer 'p' inside an object of class Foo and another
pointer 'q' in class Bar is pointing to 'p' (a double indirection), it surely
is *not* a waste of time setting 'p' to NULL after it's deleted, whether you
use '*q' or not, because it's a dangling pointer.
Also, setting a pointer to NULL after it's deleted fills that word of memory
with an invalid pointer value. If that word of memory is reallocated as
storage for another object (which is very likely), it starts out life as a
fairly safe value in the new object. This is especially useful if
programmers are lax about initializing all the members of a class in their
constructors. (It's a flaw of C++ that it doesn't initialize all non-class
type members (ints, enums, floats, and pointers) to zero by default anyway).
This prompts me to state another good rule to follow:
Initialize every member of a class when it's constructed.
Setting a pointer to NULL after it's deleted follows the complementary rule:
Set every variable to a 'safe' value when it's no longer needed,
especially pointers.
Coding this way is known generally as "defensive programming", i.e., doing
extra things to protect yourself from disaster occurring as a result of
badly written code (which may not be yours) that executes later in the
program.
I'll state the original rule again, for emphasis:
A pointer should *always* be set to NULL immediately after it's deleted
(i.e., after the object it points to is deleted). Otherwise, it's in
an undefined state (by definition, since the compiler is free to modify
it during the delete operation).
If you think this is inefficient because you know you'll never reference that
pointer again, you've just allowed a lurking bug to exist. How sure can you
be? What about when the program is altered months later? If you think that
extra CPU instruction is a waste of time, consider that the compiler could
optimize it out if it thinks there are no more further references to the
pointer.
-- David R. Tribble, david.tribble@central.beasys.com --
---
[ 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: mseitz@meridian-data.com (Matt Seitz)
Date: 1997/01/15 Raw View
In article <2.2.32.19970114174340.002de65c@central.beasys.com>, David R Tribble <david.tribble@central.beasys.com> wrote:
>Therefore, the correct "style" is to set 'p' to NULL immediately
>after it's been deleted.
>This is a coding "style" that should be followed without question
>after every delete statement
That makes sense to me, but I have to wonder: if one should always set a
pointer to NULL following a delete, then why doesn't delete just automatically
set the pointer to NULL?
[ 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: aGriffiths@ma.ccngroup.com (Alan Griffiths)
Date: 1997/01/16 Raw View
In article: <2.2.32.19970114174340.002de65c@central.beasys.com> David R Tribble <david.tribble@central.beasys.com> writes:
>
> > int* p = new int;
> > ...
> > delete p;
> > delete p;
>
> This is bad "style" because it doesn't follow the rules, which leads
> to undefined behavior. Once an object has been deleted via a
> pointer, that pointer is in an undefined state. The compiler is free
> to modify the pointer (!) during the deletion operation. Also, it's
> obvious that the pointer is no longer valid (a dangling pointer)
> after the delete, since it's not pointing to any valid object. The
> second delete statement exposes the danger of this undefined state of
> 'p'. If 'p' is anything other than NULL, the second delete will also
> result in undefined (and probably catastrophic) behavior.
>
> Therefore, the correct "style" is to set 'p' to NULL immediately
> after it's been deleted. This preserves the semantics of the deletion
> operation, and puts the pointer into a known, stable state.
> Any subsequent deletes of 'p' will then operate benignly.
>
> This is a coding "style" that should be followed without question
> after every delete statement (even if the pointer variable is about to
> go out of scope), but too few programmers are diligent enough to do
> that. That's the sort of sloppy coding that leads to memory leaks,
> double deletions, and dangling pointers.
Actually, having "delete" explicitly in client code is bad style, it
should only occur in the destructor or assignment operator of smart
pointer templates (or other objects whose sole purpose is to manage
a memory resource). Anything else become unmanagable in the presence
of exceptions.
Given this style, setting the pointer to null is obviously pointless as
it is either about to disappear, or to be reassigned.
Similarly "new" should only occur as part of the construction (ctor
argument or initialisation) of such a management object.
__
Alan Griffiths | Tel. . . . : +44 115 934 4517
Senior Systems Consultant, | CompuServe : 100142,2007
CCN Group Limited. | Home . . . : alan@octopull.demon.co.uk
(agriffiths@ma.ccngroup.com) | _usual disclaimers_
---
[ 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: Richard Krehbiel <rich@kastle.com>
Date: 1997/01/16 Raw View
David R Tribble <david.tribble@central.beasys.com> writes:
> >>That makes sense to me, but I have to wonder: if one should always set a
> >>pointer to NULL following a delete, then why doesn't delete just
> >>automatically set the pointer to NULL?
>
> Good question. You aren't the first person to suggest this, and I agree with
> the idea.
I agree with the sentiment. I don't agree with the solution. I'd
rather delete behave uniformly, and not have a side effect that is
sometimes carried out and sometimes not.
> >Furthermore, there's no requirement that the argument to delete be a
> >modifiable lvalue.
>
> True. But then again, the compiler knows it's not an lvalue. It could also
> detect the following case, and still (properly) set the pointer to NULL:
>
> const char * p = new char[len];
> ...
> delete const_cast<char *> p; // Constness cast away
But delete may be given a real true-to-life rvalue.
char *remotefunc();
delete remotefunc();
Also note that a #define like the following will give you what you're
asking for:
#define DISPOSE(x) do { delete x; x = NULL; } while(0)
Just watch out for side effects in x, which is evaluated twice. (I'm
not good at templates; I suspect a template could do the same thing
without the side effect problem.)
> >Finally, there's a simple efficiency argument. If you never reference a
> >pointer variable after deleting it, it's a waste of time setting it to
> >NULL.
Using the above macro, if x is an automatic variable, then the
compiler will likely optimize away the assignment; it can see that the
next thing that happens to it is going out of scope.
--
Richard Krehbiel, Kastle Systems, Arlington, VA, USA
rich@kastle.com (work) or richk@mnsinc.com (personal)
---
[ 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: David R Tribble <david.tribble@central.beasys.com>
Date: 1997/01/14 Raw View
> int* p = new int;
> ...
> delete p;
> delete p;
This is bad "style" because it doesn't follow the rules, which leads
to undefined behavior. Once an object has been deleted via a
pointer, that pointer is in an undefined state. The compiler is free
to modify the pointer (!) during the deletion operation. Also, it's
obvious that the pointer is no longer valid (a dangling pointer)
after the delete, since it's not pointing to any valid object. The
second delete statement exposes the danger of this undefined state of
'p'. If 'p' is anything other than NULL, the second delete will also
result in undefined (and probably catastrophic) behavior.
Therefore, the correct "style" is to set 'p' to NULL immediately
after it's been deleted. This preserves the semantics of the deletion
operation, and puts the pointer into a known, stable state.
Any subsequent deletes of 'p' will then operate benignly.
This is a coding "style" that should be followed without question
after every delete statement (even if the pointer variable is about to
go out of scope), but too few programmers are diligent enough to do
that. That's the sort of sloppy coding that leads to memory leaks,
double deletions, and dangling pointers.
That's one of the strengths that other object-oriented languages (like
Java and Eiffel) have over C++, that they manage pointers (references)
to objects for you, so these kinds of bugs can't happen.
[ 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 ]