Topic: delete inefficient due to NULL check


Author: brangdon@cix.co.uk (Dave Harris)
Date: Sat, 19 Jun 2004 23:32:25 +0000 (UTC)
Raw View
petebecker@acm.org (Pete Becker) wrote (abridged):
> > Personally I'd rather have the convenience of not checking for NULL in
> > user code, but I appreciate that in some situations the time cost of
> > the check may be significant.
>
> Well, there's significant and there's significant. Adding 50% to an
> ultra-fast delete operation probably doesn't introduce a performance
> bottleneck. So 50% may sound significant, but it isn't really
> significant.

"Probably" yes, but in some situations it might do. The allocation would
also need to be fast, of course (which it probably would be), and there
would have to be very little work done in between. So I imagine it would
be a fairly degenerate case. The concern is mostly academic.

-- Dave Harris, Nottingham, UK

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Tue, 15 Jun 2004 17:59:35 +0000 (UTC)
Raw View
tom_usenet@hotmail.com (tom_usenet) wrote (abridged):
> Have you measured the time taken to do a single NULL comparison
> compared to the time taken by a delete expression? I suspect the first
> takes around 1/1000th of the time of the second...

That will depend on the implementation. A reasonable implementation could
keep an array of free lists of uniform block-size, indexed by the size of
the block (with suitable rounding). For a single known POD the compiler
knows the size at compile time, so the code is like:

    // delete p;
    reinterpret_cast<Block *>(p)->next = pHead_16;
    pHead_16 = reinterpret_cast<Block *>(p);

Just 2 assignments. This can be inlined if the compiler can show the
global operator delete has not been replaced (eg in a JIT environment). An
"if" statement could add substantially to this, as it will make demands on
the CPU's branch-prediction architecture. The cost is going to be more
like 50% than 0.1%. Allocation can be almost as fast.

Personally I'd rather have the convenience of not checking for NULL in
user code, but I appreciate that in some situations the time cost of the
check may be significant.

-- Dave Harris, Nottingham, UK

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: matsw@bluewin.ch (Mats Weber)
Date: Tue, 15 Jun 2004 18:12:53 +0000 (UTC)
Raw View
I would like delete to be even more inefficient and safer, by setting
its argument to 0 once the object it points to is deleted. This would
avoid many bugs with dangling pointers.

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: petebecker@acm.org (Pete Becker)
Date: Tue, 15 Jun 2004 19:10:20 +0000 (UTC)
Raw View
Dave Harris wrote:
>
> Personally I'd rather have the convenience of not checking for NULL in
> user code, but I appreciate that in some situations the time cost of the
> check may be significant.
>

Well, there's significant and there's significant. Adding 50% to an
ultra-fast delete operation probably doesn't introduce a performance
bottleneck. So 50% may sound significant, but it isn't really
significant.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: petebecker@acm.org (Pete Becker)
Date: Tue, 15 Jun 2004 19:21:17 +0000 (UTC)
Raw View
Mats Weber wrote:
>
> I would like delete to be even more inefficient and safer, by setting
> its argument to 0 once the object it points to is deleted. This would
> avoid many bugs with dangling pointers.
>

And it would encourage progammers to rely on this behavior, to their
peril:


void f(int *ip)
{
delete ip;
}

void huh()
{
int *ip = new int;
f(ip);
if (ip)
 // do something
}

To avoid bugs with dangling pointers don't create dangling pointers.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: musiphil@bawi.org (Seungbeom Kim)
Date: Tue, 15 Jun 2004 22:45:37 +0000 (UTC)
Raw View
Mats Weber wrote:

> I would like delete to be even more inefficient and safer, by setting
> its argument to 0 once the object it points to is deleted. This would
> avoid many bugs with dangling pointers.

I can think of two reasons right now
why this can't happen or be as useful as one might expect:

1. The argument of delete doesn't have to be an lvalue,
     so delete cannot change the value of the argument.
     (ex) delete p+1;

2. There may be more than one pointer to the object being deleted,
     and delete cannot enumerate and nullify all the pointers.
     (ex) int* p = new int;
          int* q = p;
          delete q;  // Should p be NULL after this? How?

There may be more. If you want to avoid bugs with dangling pointers,
I would suggest using a smart pointer (such as boost::shared_ptr).

--
Seungbeom Kim

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: jackklein@spamcop.net (Jack Klein)
Date: Wed, 16 Jun 2004 00:34:24 +0000 (UTC)
Raw View
On Mon, 14 Jun 2004 16:15:12 +0000 (UTC), francis@robinton.demon.co.uk
(Francis Glassborow) wrote in comp.std.c++:

> In article <gpaqc0t0agg4qen54ee7ttedoh1c04orir@4ax.com>, Jack Klein
> <jackklein@spamcop.net> writes
> >Finally, I think this is rather a tempest in a teapot.  The overhead
> >of a single:
> >
> >   if(!pointer)
> >
> >..has to be considerably less than the actual task of releasing a
> >block of memory that contains only primitive types without
> >destructors.  I would say by an order of magnitude or more in this
> >simplest case, and much more in cases where arrays of classes with
> >destructors are involved.
>
> And note that the developer of a high quality library always has the
> option to implement the function in assembler where that test is a
> single instruction on most hardware. Compare that with forcing the user
> to make the test with an explicit instruction such as the above. Now we
> have to rely on compiler quality rather than quality of library
> implementation. I think the choice made is exactly the right one and is,
> by and large, an example of timely optimisation.

And, not completely off-topic here because <cstdio> is part of the
standard C++ library, I have always wondered why fclose(NULL) was not
defined a harmless no-op as well, by analogous reasoning.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Michiel.Salters@logicacmg.com (Michiel Salters)
Date: Wed, 16 Jun 2004 15:45:52 +0000 (UTC)
Raw View
kprateek88@yahoo.com (Prateek R Karandikar) wrote in message news:<607f883e.0406120802.483a67fc@posting.google.com>...
> delete does nothing if its is operand is 0. This means that delete
> would have to check for zero, and if the operand is not zero, then
> call the dtor, deallocate the memory, etc.

delete is a built-in. The compiler can optimize it; it may be able
to omit the null check. E.g. in the following sequence

p->foo();
delete p;

a compiler does not have to include the check. The following
is not so obvious:

assert(p);
delete p;

but I would not object to a compiler that optimizes this too.

Regards,
Michiel Salters

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dietmar_kuehl@yahoo.com (Dietmar Kuehl)
Date: Wed, 16 Jun 2004 16:23:31 +0000 (UTC)
Raw View
matsw@bluewin.ch (Mats Weber) wrote:
> I would like delete to be even more inefficient and safer, by setting
> its argument to 0 once the object it points to is deleted. This would
> avoid many bugs with dangling pointers.

It would create a false sense of security and, IMO, would encourage people
to write buggy code! The problem is that pointers can be copied. Actually,
I don't see any problems with dangling pointers anyway: since I handle
object ownership explicitly I had very few of these - and those I had were
logic errors in other places (eg. wrong handling of reference counts on
CORBA or COM objects).
--
<mailto:dietmar_kuehl@yahoo.com> <http://www.dietmar-kuehl.de/>
<http://www.contendix.com> - Software Development & Consulting

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: qrczak@knm.org.pl ("Marcin 'Qrczak' Kowalczyk")
Date: Wed, 16 Jun 2004 18:38:58 +0000 (UTC)
Raw View
On Tue, 15 Jun 2004 18:12:53 +0000, Mats Weber wrote:

> I would like delete to be even more inefficient and safer, by setting
> its argument to 0 once the object it points to is deleted.

This would provide a false sense of security, because it would not set any
other pointer variable which points to the same object to NULL. It would
break uses of delete whose argument is not an lvalue.

--
   __("<         Marcin Kowalczyk
   \__/       qrczak@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/


---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kprateek88@yahoo.com (Prateek R Karandikar)
Date: Sat, 12 Jun 2004 18:21:00 +0000 (UTC)
Raw View
delete does nothing if its is operand is 0. This means that delete
would have to check for zero, and if the operand is not zero, then
call the dtor, deallocate the memory, etc. IMHO, this goes against the
C++ tradition of efficiency. Wouldn't it have been more efficient if
calling delete on the null pointer (just like dereferencing it) was
undefined? After that it would have been trivial to implement a "safe
delete" if the user wanted:

tempate <typename T>
void safe_delete(T *p){if(p) delete p;} //If deleting a null ptr was
UB
//similarly for delete[]

In that scenario the user would have the option of calling safe_delete
or the plain delete. However, in the present scenario, there is no way
of telling delete : "I know for sure the pointer isn't 0, so don't
check".

It is easy to define a safer, less efficient facility on top of a less
safe, more efficient facility, but not the other way round. Nowhere
else in C++ (that I can remember of at the moment) is any operation
checked by default, especially where the check can be added easily by
the user.

Suppose a class has a pointer member, and the invariant of the class
is: "the pointer member points to memory allocated by new" In that
case the destructor will know that the ptr is never 0, and so would
not need the check.

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
To iterate is human, to recurse divine.
-L. Peter Deutsch
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: jackklein@spamcop.net (Jack Klein)
Date: Mon, 14 Jun 2004 05:03:01 +0000 (UTC)
Raw View
On Sat, 12 Jun 2004 18:21:00 +0000 (UTC), kprateek88@yahoo.com
(Prateek R Karandikar) wrote in comp.std.c++:

> delete does nothing if its is operand is 0. This means that delete
> would have to check for zero, and if the operand is not zero, then
> call the dtor, deallocate the memory, etc. IMHO, this goes against the
> C++ tradition of efficiency. Wouldn't it have been more efficient if
> calling delete on the null pointer (just like dereferencing it) was
> undefined? After that it would have been trivial to implement a "safe
> delete" if the user wanted:
>
> tempate <typename T>
> void safe_delete(T *p){if(p) delete p;} //If deleting a null ptr was
> UB
> //similarly for delete[]

   [snip]

I can think of two reasons for this.

Reason 1 is for C compatibility, since the original C standard which
C++ inherits requires that free() (std::free() in C++) do nothing with
a null pointer, under the assumption that anything returned by
malloc() should be passable to free().

Reason 2 is that early versions of C++, prior to the addition of
exceptions to the draft standard, required operator new ([]) to return
a null pointer on failure, rather than throw an exception.  And there
are still options to have new do so rather than throw.

A corollary to these reasons is the fact that many, if not most or
all, C++ implementations use the underlying C library as their
interface to the platform's underlying memory allocation mechanism.
They are allowed to do so, and it tends to make sense since these
functions are also part of the standard C++ library and so must be
available.

Finally, I think this is rather a tempest in a teapot.  The overhead
of a single:

   if(!pointer)

..has to be considerably less than the actual task of releasing a
block of memory that contains only primitive types without
destructors.  I would say by an order of magnitude or more in this
simplest case, and much more in cases where arrays of classes with
destructors are involved.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: tom_usenet@hotmail.com (tom_usenet)
Date: Mon, 14 Jun 2004 16:15:09 +0000 (UTC)
Raw View
On Sat, 12 Jun 2004 18:21:00 +0000 (UTC), kprateek88@yahoo.com
(Prateek R Karandikar) wrote:

>delete does nothing if its is operand is 0. This means that delete
>would have to check for zero, and if the operand is not zero, then
>call the dtor, deallocate the memory, etc. IMHO, this goes against the
>C++ tradition of efficiency. Wouldn't it have been more efficient if
>calling delete on the null pointer (just like dereferencing it) was
>undefined?

Have you measured the time taken to do a single NULL comparison
compared to the time taken by a delete expression? I suspect the first
takes around 1/1000th of the time of the second...

Tom
--
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Mon, 14 Jun 2004 16:15:12 +0000 (UTC)
Raw View
In article <gpaqc0t0agg4qen54ee7ttedoh1c04orir@4ax.com>, Jack Klein
<jackklein@spamcop.net> writes
>Finally, I think this is rather a tempest in a teapot.  The overhead
>of a single:
>
>   if(!pointer)
>
>..has to be considerably less than the actual task of releasing a
>block of memory that contains only primitive types without
>destructors.  I would say by an order of magnitude or more in this
>simplest case, and much more in cases where arrays of classes with
>destructors are involved.

And note that the developer of a high quality library always has the
option to implement the function in assembler where that test is a
single instruction on most hardware. Compare that with forcing the user
to make the test with an explicit instruction such as the above. Now we
have to rely on compiler quality rather than quality of library
implementation. I think the choice made is exactly the right one and is,
by and large, an example of timely optimisation.


--
Francis Glassborow      ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]