Upload
edgar-norton
View
214
Download
0
Embed Size (px)
DESCRIPTION
Name Hiding The designers of C++ decided that overloaded functions cannot be inherited in a child class. The child class version of the overloaded function “hides” the parent class version. This is a good way to avoid some tricky ambiguities, apparently. See TestHiding.cpp Fall 2015CISC/CMPE320 - Prof. McLeod3
Citation preview
Fall 2015 CISC/CMPE320 - Prof. McLeod 1
CISC/CMPE320• Assignment 3 is due Sunday, the 8th at 7pm.
• Today:– Two simple binding examples.– Function Hiding.– Memory in General.– The Heap.– Common Memory Issues.
More Function Binding Examples• Static binding is determined at compilation.• Dynamic binding is determined at run time.
• See:– TestStaticBinding.cpp– TestDynamicBinding.cpp
Fall 2015 CISC/CMPE320 - Prof. McLeod 2
Name Hiding• The designers of C++ decided that overloaded
functions cannot be inherited in a child class.• The child class version of the overloaded function
“hides” the parent class version.• This is a good way to avoid some tricky
ambiguities, apparently.
• See TestHiding.cpp
Fall 2015 CISC/CMPE320 - Prof. McLeod 3
Name Hiding, Cont.• You can get around this by using “using” in the
child class as shown in the demo.
• However, this is considered poor practice.
• It is less confusing to avoid trying to overload inherited functions and just use different function names instead.
Fall 2015 CISC/CMPE320 - Prof. McLeod 4
Fall 2015 CISC/CMPE320 - Prof. McLeod 5
Memory Categories• Code: Machine instructions for all member and
non-member functions. Code is read from memory and executed.
• Static Data: All global variables and static local variables and static class data members.
• Run-time Stack: Used by most variables. All local, non-static variables.
• Free Store or Heap: Used when variables are created using the new keyword.
Stack vs. Heap Memory• The stack is a fixed size amount of RAM
consisting of sequential addresses.• Every time a function is invoked a frame is
pushed on top of the stack. The frame contains:– Function arguments.– Local variables.– The code memory location for the instruction that
invoked the function.– Another code instruction counter.– A memory location waiting to accept other return
values.
Fall 2015 CISC/CMPE320 - Prof. McLeod 6
Aside – Changing Stack Size• Default is about 2MB.• Lots – unless you create large arrays on the stack
(why?) or you are doing a lot of recursion.• To increase add the following to the
“miscellaneous” linker command line options:
-Wl,--stack,<size>
• <size> is in bytes. This assumes gcc/mingw on Windows. (I have not tried this…)
Fall 2015 CISC/CMPE320 - Prof. McLeod 7
Stack vs. Heap Memory, Cont.• When a function completes, the frame is popped
off the stack (effectively, a stack pointer which contains the address of the top frame on the stack is moved to the frame below the frame that finished).
• The next frame, resulting from another function call, overwrites some or all of the memory from the old frame (and the stack pointer is moved up to the new frame).
Fall 2015 CISC/CMPE320 - Prof. McLeod 8
Stack vs. Heap Memory, Cont.• This does not happen with heap memory. Objects
in the heap persist and you must delete them!• Heap memory is only limited by the amount of
RAM that can be obtained by your OS.• Addresses are not necessarily sequential.• If you run out of RAM in your heap, then you may
start using a swap file (yuk!).• Stack overflow is common – when you run out of
stack memory.• But the heap is huge!! No overflow problems. But
you might have a memory leak problem instead!Fall 2015 CISC/CMPE320 - Prof. McLeod 9
Fall 2015 CISC/CMPE320 - Prof. McLeod 10
Heap Memory• You don’t always know until run-time how big an
object will need to be. It might be huge!• You may not be able to use (or may not want to
use) a global, but need to have a variable that persists beyond a function’s completion.
• This memory is allocated when you use the new operator.
• The new operator provides dynamic memory allocation – a “memory allocator” process supplies the address of a heap storage location.
• You must use a pointer to refer to something on the heap. The pointer will be on the stack.
Returning a Pointer• If you create a local object on the heap in a
function then you can return a pointer to that object and it will persist.
• Much better than returning a reference to a local object!
• To illustrate one difference between run-time stack memory and the heap see TestHeap.cpp.
• Test the effects of size and persistence.
Fall 2015 CISC/CMPE320 - Prof. McLeod 11
Fall 2015 CISC/CMPE320 - Prof. McLeod 12
Heap Memory, Cont.• To return memory to the heap, you must use the delete operator. To free up an array, use delete[]. Supply a pointer to the operator.
• When you use new to create an array the size does not have to be known until run time:
double* a = new double[arraySize];
• The pointer a will reside on the run-time stack, but the array structure will be on the heap.
Destructor Member Function• Distinguished from a constructor using the ~
before the class name.• Responsible for deleting all heap variables.• If you use the heap in your class you must have a
destructor.
• One of “The Big Three”:
Fall 2015 CISC/CMPE320 - Prof. McLeod 13
Fall 2015 CISC/CMPE320 - Prof. McLeod 14
“The Big Three” – Summary• Destructor:
– Frees all heap memory used by the object.• Copy constructor:
– Initializes the object as a copy of the same type object supplied as a parameter. If you are using heap memory you will need to allocate and initialize each value.
• Assignment operator:– Check to make sure that you are not assigning yourself.
If so, do nothing.– Free up the heap memory that is no longer needed.
Copy the value of the argument supplied.– Return *this.
“The Big Three”
• More on these guys later.
• For now, look at some common errors created by improper use of memory in C++.
• Using the heap makes it much easier for the coder to create errors!
Fall 2015 CISC/CMPE320 - Prof. McLeod 15
Fall 2015 CISC/CMPE320 - Prof. McLeod 16
Common Memory Errors• Using a variable that has not been initialized.• Using a pointer to reference a memory location
that is no longer valid.• Forgetting to delete something on the heap.• Deleting a memory value that was never
allocated.• Deleting something on the heap more than once.
• Look at each of these, in turn:
Fall 2015 CISC/CMPE320 - Prof. McLeod 17
Initialization Memory Errors• We’ve seen this one before.• A variable or pointer is created, but not initialized.• Includes creating an array on the heap, but not
initializing its elements.
• You don’t get an error, you just get some random value – whatever happens to be in that memory location.
Fall 2015 CISC/CMPE320 - Prof. McLeod 18
Lifetime Memory Errors• Seen this one before, too:
• When an activation record is popped off the run-time stack it takes all its local variables with it – they are no longer valid.
• If you have returned a pointer to a local variable, that location will only be valid until the next function invocation occurs.
• It is likely that this location will be overwritten.
Fall 2015 CISC/CMPE320 - Prof. McLeod 19
Lifetime Memory Errors, Cont.• For example:
char* readALine() {char buffer[200];cin >> buffer;return buffer;
}char* p = readALine();
• p is called a “dangling pointer” as it is pointing to memory that is no longer valid after readALine() is finished.
Fall 2015 CISC/CMPE320 - Prof. McLeod 20
Aside – Buffer Overflow Error• Consider that readALine() function again:• Suppose the user entered more than 200
characters:– In this case, the extra characters would end up
being written to memory beyond the dimensions of the array.
– This used to be a popular way for virus writers to inject their own function into an application.
– If you can overwrite the return address of the activation frame to the address of your function…
Fall 2015 CISC/CMPE320 - Prof. McLeod 21
Lifetime Memory Errors, Cont.• You can cause similar behaviour if you attempt to
return a reference to a local variable. For example:
Fraction& operator+(const Fraction& left, const Fraction& right) {
Fraction result(left.numer() * right.denominator() + right.numer() * left.denominator(), left.denominator() * right.denominator()); return result;}
Get rid of this
Fall 2015 CISC/CMPE320 - Prof. McLeod 22
Memory Leaks• When you forget to delete something on the heap.• More likely to cause a problem in a long-running
program.• Suppose you have successive re-assignments to
the same pointer variable inside a loop.• If you don’t carry out a delete in-between
assignments each object remains on the heap.• Eventually the heap manager will be unable to
service any new requests.
Fall 2015 CISC/CMPE320 - Prof. McLeod 23
Invalid Memory References• What happens when you are too eager to delete a
value from the heap.• If you have more than one pointer aliased to that
value, then the second pointer becomes invalid.• For example, deleting the nodes of a linked list in
a for loop:
for (Node* p = ptr; p != NULL; p = p->next)delete p;
}• p->next is no longer accessible after deletion.
Fall 2015 CISC/CMPE320 - Prof. McLeod 24
Aside – Using nullptr• You can assign a pointer to be nullptr. (It does
not happen by default as in Java!).• Deleting a null pointer has no effect.• So, consider setting a pointer to nullptr after
you have deleted it:– This will prevent you trying to invoke any functions from
the pointer (you will get a null pointer error).– And if you do try to delete the pointer again, nothing
bad will happen.
Fall 2015 CISC/CMPE320 - Prof. McLeod 25
Deleting an Un-Initialized Pointer
Fraction* frac;delete frac;
• Bad news. You are trying to delete garbage.• Better to set to nullptr if you cannot initialize
right away:
Fraction* frac = nullptr:delete frac;
Fall 2015 CISC/CMPE320 - Prof. McLeod 26
Object Slicing• Another memory problem that is particular to C++.• For example:
Child* c = new Child(arguments…);Parent* p = c; // OKParent pp = *c; // NOT OK
• This is legal, compiles and runs fine, but what is the problem with the last line?
Fall 2015 CISC/CMPE320 - Prof. McLeod 27
Object Slicing, Cont.• The portion of the Child object that will not fit
into an object of type Parent is “sliced” away – it is lost, when the pointer, c, is de-referenced.
• This is one of the reasons why it is best to access objects through pointers or references only.
Fall 2015 CISC/CMPE320 - Prof. McLeod 28
Polymorphism – Peeking…• A dynamic cast can be used to determine what
kind of object you actually have.• If the cast fails a nullptr is returned.
• For example:Child* c = dynamic_cast<Child*>(object);
• c will be nullptr if object is not a Child or a parent of Child.
Fall 2015 CISC/CMPE320 - Prof. McLeod 29
Peeking, Cont.• Note that a static_cast<Child> will not check
to see if the type will work.• You don’t get a nullptr, you just get a
problem…
• It is best to just use static_cast<type> with primitive types only.
Fall 2015 CISC/CMPE320 - Prof. McLeod 30
More Peeking• The typeid() operator is a more general way of
determining an object’s type.• It is obtained from the <typeinfo> library.• Remember to de-reference a pointer in order to
compare its type.• For example:
if (typeid(*pointer) == typeid(type)) …