Redefining new & delete
Description
In this lab, we’ll show how you can redefine the new/delete operators
to achieve a variety of useful or bizarre results.
                
The files for this lab are available in
~cs253/Lab/New.
                
1. Redefining global new/delete
Consider glob.cc. It redefines the global new
and delete
operators (yes, operators) to add trace output.
This could be useful in figuring out just when new
and delete
are being invoked.
                
Note the function signatures—at this level, new
takes a
size_t
and returns a void *
, whereas delete
takes a void *
and
a size_t
and returns void
.
Why does new
return void *
?
                
2. Redefining class-specific new
/delete
Consider class.cc. It redefines the
class-specific new
and delete
operators to add trace output.
This will not affect new
and delete
operations on other types,
such as int
or double
.
- Run the code, consider the output. Now explain briefly, for each line
of
main
, which function is called and why?
- Why are
operator new
and operator delete
declared static
?
3. Forbid new
/delete
for a specific class
Try to compile forbid1.cc.
Does it compile? Why not?
                
4. Same thing, but using =delete
Try to compile forbid2.cc.
Does it compile? Why not?
                
5. Same thing, but with a Mixin
forbid-mixin.cc does the same thing as
forbid1.cc & forbid2.cc,
but encapsulates it in a “mixin”.
                
Why does the mixin class declare its ctor & dtor protected
?
                
For another popular example of a mixin, see
the Boost class
noncopyable
                
6. Error checking
Compile and execute errchk.cc.
Observe the error message, and decide what caused it. How would you
improve it to detect multiple deletions of the same memory? (You don’t
need to write the code, just explain it.)
                
7. Scrubbing the memory
There are several reasons for scrubbing memory.
- At
new
time, to ensure that you’re not erroneously counting
on the memory being any particular value.
- At
delete
time, if you fear that the code may erroneously keep
pointers to the deleted memory.
Consider the technique used in scrub.cc.
What criteria would you use to decide on a value for memory? It should be:
- a lousy integer
- a lousy floating-point value
- a lousy pointer
- a printable value
For example, a repeated string of “Jack” or “WTF!” would fit all of the
above requirements. Notably, an odd value makes for a poor pointer, and
may cause a segmentation violation upon use, since some architectures
require a four-byte int
to be at an address that’s a multiple of
four.
                
8. Memory pooling
Run normal.cc.
- What is the size of
class Foo
?
- What is the difference between the values of
p
and q
? Why?
Now, run pool.cc.
- What is the size of
class Bar
?
- What is the difference between the values of
r
and s
? Why?
9. Templated version
Of course, it’s a pain to have to redefine new
and delete
for every class. After we study templates, you will be able to
create a templated mixin to do the same for all classes.
                
10. Problems with this approach
- What if you redefine
new
and delete
for class Foo
,
and then derive class Bar
from class Foo
?
- Will
Bar
inherit the redefined new
and delete
?
- Will that work, if
sizeof(Bar) > sizeof(Foo)
?
- How would you fix that?
11. Exercises
- Measure the speed of normal.cc vs.
pool.cc. They’re too fast to measure, so you have to
modify them to run longer, for at least two seconds. Which is faster?
Why?
- Measure the space requirements of normal.cc vs.
pool.cc. They will have to be similarly modified.
12. For extra fame & glory
- Create a verion of errchk.cc that uses
backtrace to print a stack backtrace in case of error.
- Create a mixin class that does the opposite of what
NoNewDelete
in
forbid-mixin.cc does—it makes its subclass
require the use of new
.