new & delete Lab                
Description                
The files for this lab are available in
~cs253/Lab/New
. In this lab, we’ll show how
you can redefine the new/delete operators to achieve a variety of
useful or bizarre results. Record your answers to the questions asked
in a file called results.txt
, and check them in (see below).
A video introduction is available.
                
new and delete are operators. We use them like this:
                
constexpr int SIZE = 20;
int *p = new int[SIZE];
for (int i=0; i<SIZE; i++)
p[i] = i*i; // table of squares
for (int i=0; i<SIZE; i++)
cout << p[i] << ' ';
delete[] p;
0 1 4 9 16 25 36 49 64 81 100 121 144 169 196 225 256 289 324 361
I don’t see any parentheses, so new isn’t a function, it’s an
operator. Of course, when we override an operator, to provide our own
implementation, we write a function. Therefore, we write functions
named operator new and operator delete.
                
1. Redefining global new/delete                
Consider glob.cc
. It redefines the global new and
delete 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 *, as opposed to int *,
or double *, or whatever type we’re allocating?
                
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.
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”.
                
A “mixin” is a base class, designed for inheritance, but don’t think of
it as an “is-a” relationship. Instead, think of the base class as
contributing methods to the derived class. It’s similar to how they mix
chocolate sprinkles or crushed cookies into ice cream at places like
Cold Stone Creamery.
                
Why does the mixin class declare its ctor &
dtor protected?
                
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 is the best byte value to use for writing to memory? For example,
zero is a poor choice, because it makes nice zero integers and zero
floating-point values. You want something more disruptive, more
obvious, something that makes a poor int, double, pointer, or
string. Explain your reasoning.
                
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?
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.
                
9. Problems with memory pooling                
- 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?
10. Speed                
- 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 several seconds. Instead of only allocating one
or two objects, allocate ten million of them, one at a time (but
don’t free the memory between allocations). That should be big
enough to measure.
- What is the ratio of time used between the two? Why?
- Don’t bother deleting the allocated objects. This is a lab; we can
break the rules.
- To find out how long the program runs, use the time
program like this, to display the elapsed time in seconds:
/bin/time -f %e ./a.out
For example, where the initial %
is my shell prompt:
% /bin/time -f %e sleep 0.123456789
0.12
11. Space                
- Measure the space requirements of
normal.cc
vs.
pool.cc
.
- Leave the modifications from the Speed exercise in place.
- What is the ratio of memory used between the two? Why?
- Surprisingly, the
time
command can also measure how
much space (in kilobyte chunks) a command uses, like this:
% /bin/time -f %M date
Fri Aug 30 18:16:32 MDT 2024
1968
12. For extra fame & glory (but no points)                
- 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, and so forbids declaring one on the
stack.
How to submit your work:                
In Canvas, check in the
file
results.txt
to the assignment “Lab09”.
It’s due 11:59ᴘᴍ MT Saturday, with a 24-hour late period for a 25% penalty.
                
How to receive negative points:                
Turn in someone else’s work.