Set 16: Vector and Free Store

advertisement
CSCE 121:509-512
Introduction to Program Design and Concepts, Honors
Dr. J. Michael Moore
Spring 2015
Set 16: Vector and Free Store
CSCE 121-200: Set 16: Vector and
Based on slides created by
Bjarne
Free
Store Stroustrup and Jennifer Welch
1
Vector’s Virtues
• Vector is most useful container: use it to store
elements unless you have a good reason not
to
– Simple
– Compactly stores element of a given type
– Efficient access
– Expands to hold any number of elements
– Option for range checking
• How is it done?
CSCE 121:509-512
Set 16: Vector and Free Store
2
How is Vector Implemented?
We will study this and learn about
• Pointers
• Free store: allocating, accessing, deallocating
• Destructors
• Initialization, copying and moving
• Arrays
• Changing size
• Templates
• Range checking and exceptions
CSCE 121:509-512
Set 16: Vector and Free Store
3
Rationale for Studying Vector
Implementation
• Real-world case study to motivate these
concepts and their C++ instantiations
• Understand bridge from low-level hardware to
high-level services
• Hardware only provides memory and
addresses:
– Untyped
– Fixed size
– No checking
CSCE 121:509-512
Set 16: Vector and Free Store
4
Review of Computer Memory
• Local variables “live on the
stack”
• Global variables are “static
data”
• Executable code is in the
“code section”
• Free store (heap) is subject
of this lesson
CSCE 121:509-512
Set 16: Vector and Free Store
5
Vector, Take 1
//very simplified vector of doubles
class vector {
int sz;
// number of elements
double* elem; // pointer to first element
public:
vector(int s); // constructor; more later
int size() const { return sz; }
};
What is going on with double*?
CSCE 121:509-512
Set 16: Vector and Free Store
6
Pointer Values
• Pointer values are memory addresses
– Think of them as a kind of integer
– The first byte of memory has address 0, the next 1, etc.
– A pointer variable p can hold the address of a memory
location
• A pointer points to an object of a given type
– E.g., a double* points to a double, not to a string
• A pointer’s type determines how the memory
referred to by the pointer’s value can be used
0
1
2
p
600
CSCE 121:509-512
Set 16: Vector and Free Store
600
220-1
7
7
Pointer Syntax and Terminology
• To declare a variable p as a pointer to an object of type
int (p holds the address of an object of type int):
int* p;
– Note: You can also say “int *p;” but be careful when
declaring multiple variables on same line
– “int *px, py;” makes px a pointer and py an int)
• To get to the object that p points to (to access its
value), we have to dereference p:
*p = 5;
// changes memory whose address is stored
// in p, not the data stored in location p
int y = 4 + *p; // y holds 9
• Pointers can point to object of any type
CSCE 121:509-512
Set 16: Vector and Free Store
8
Pointer vs. Reference
• Think of a reference as an automatically
dereferenced pointer
– you do not need to use the * (dereference)
operator to get to the value
– thus it is an alternative name for an object
• Differences from pointer:
– reference must be initialized
– value of a reference cannot be changed after
initialization (reference always refers to the same
object)
CSCE 121:509-512
Set 16: Vector and Free Store
9
Pointer vs. Reference Examples
int x = 7;
int y = 8;
int* p = &x;
*p = 9;
p = &y; // OK: can change which object p points to
int& r = x;
x = 10;
r = &y; // error: cannot change which object r
// refers to
CSCE 121:509-512
Set 16: Vector and Free Store
10
Pointer Hazards
• Pointers (are supposed to) hold addresses
• They really hold bit patterns that are interpreted as addresses
• If a pointer somehow holds arbitrary bits, it can refer to:
– address that doesn’t exist
– address that exists but is definitely not where you want to be!
• Reading from this (random) location returns garbage
• Writing to this (random) location corrupts memory
• Bad effects (run-time errors):
– crash the operating system
– cause memory protection exception
– produce incorrect results
CSCE 121:509-512
Set 16: Vector and Free Store
11
Mitigating Pointer Hazards
• Avoid Using Pointers When Possible
– E.g., use vector instead of arrays
• Only use pointers in very constrained
situations
• When you do use pointers, be sure to initialize
them properly:
int* pi = nullptr;
// or NULL or 0
CSCE 121:509-512
Set 16: Vector and Free Store
12
Pointing to Objects on the Stack
• You can use pointers to get the address of
objects stored in the stack using the &
(address-of) operator
int main() {
int i;
int *pi = nullptr;
pi = &i;
// pi gets address of i
*pi = 502; // assigns to i
cout << "i = " << i << endl; // outputs 502
cout << "pi = " << pi << endl; // outputs, e.g., 0x7fff503ebbb8
cout << "*pi = " << *pi << endl; // outputs 502
return 0;
}
CSCE 121:509-512
Set 16: Vector and Free Store
13
Pointing to Objects on the Heap
• An important use of pointers is to point to
objects that are allocated on the heap (free
store)
CSCE 121:509-512
Set 16: Vector and Free Store
14
Dynamic Memory Allocation
• Use the operator new to allocate a chunk of memory
on the heap
– specify the type of object to be stored and
– specify the number of objects of that type
• new returns a pointer to the first object in the chunk
• Memory allocated with new is not automatically
deallocated!
– you must do that explicitly yourself with the delete
operator
– thus you can allocate objects that outlive the function that
creates them
CSCE 121:509-512
Set 16: Vector and Free Store
15
Example Use of new
int s = 100;
double* dp = new double[s];
// Allocates space for 100
// consecutive doubles on the heap.
// To check whether new was
// successful:
if (dp == 0) error(“new failed”);
// Continue and use the space.
// If you only want one double,
// then leave off the [s]
CSCE 121:509-512
Set 16: Vector and Free Store
16
Vector, Take 1, Constructor
vector::vector(int s) // vector’s constructor
: sz(s), // store the size s in data member sz
elem(new double[s])
// allocate s consecutive doubles in free store,
// store pointer to the first double in
// data member elem
{}
// new does not initialize the elements (but the
// standard vector does)
Free store:
sz:
4
elem:
A pointer
CSCE 121:509-512
Set 16: Vector and Free Store
17
Accessing Memory Allocated on
the Heap
• Individual objects allocated in a batch by new
are accessed using the [ ] notation for
indexing, starting at 0
int* pi
pi[0] =
pi[1] =
int x =
int y =
= new int[5];
7;
9;
pi[1];
*pi; // means pi[0]
CSCE 121:509-512
Set 16: Vector and Free Store
18
A Pointer Pitfall
• A pointer actually holds the address of a byte
– the first byte of the object or sequence of objects
• A pointer does not know how many objects
have been allocated
– doesn’t know where to stop
int* pi = new int[5];
int y = -3;
pi[5] = 72; // compiles like a charm :(
pi[-4] = 12; // ditto
CSCE 121:509-512
Set 16: Vector and Free Store
19
Assigning a Pointer to a Pointer
• What happens in this case?
double* p1 = new double;
double* p2 = new double[100];
p1[17] = 9.4; // run-time or logic error
p1 = p2;
p1[17] = 9.4
// OK now
• the assignment “p1 = p2” copies the data in
p2 (the address of the start of the 100
doubles) into p1
CSCE 121:509-512
Set 16: Vector and Free Store
20
Pointers and Types
• A pointer does know the type of the object
that it is pointing to
int* pi1 =
int* pi2 =
double* pd
char* pc =
new int(7); // initialize to 7
pi1; // OK
= pi1; // compile-time error
pi1; // compile-time error
• There are no implicit conversions between a
pointer to one value type to a pointer to
another value type
CSCE 121:509-512
Set 16: Vector and Free Store
21
Pointer-Related Errors
• The following errors are often caused by
uninitialized or otherwise invalid pointers:
– segmentation fault
– bus error
– core dump
CSCE 121:509-512
Set 16: Vector and Free Store
22
Vector, Take 1, Access
class vector {
int sz;
double* elem;
public:
vector(int s) : sz(s), elem(new double[s]) { } // constructor
double get(int n) const { return elem[n]; }
// access: read
void set(int n, double v) { elem[n] = v; }
// access: write
int size() const { return sz; }
// the current size
};
// ...
vector v(10);
for (int i = 0; i < v.size(); ++i) {
v.set(i,i);
cout << v.get(i);
}
CSCE 121:509-512
Set 16: Vector and Free Store
23
A Problem: Memory Leak
double* calc(int result_size, int max) {
double* p = new double[max];
double* result = new double[result_size];
// use p to calculate values to be put in result
return result;
}
// ...
double* r = calc(200,100);
• We did not give the memory allocated for p back to
the free store but there is no way to access it once
calc is finished
• Memory leak (lack of deallocation) – can be a serious
problem in real-world programs
CSCE 121:509-512
Set 16: Vector and Free Store
24
Memory Leaks
• A program that needs to run “forever” (e.g., an
operating system) cannot afford any memory
leaks
– eventually memory leaks will use up all available
memory
• All memory is returned to the system at the
end of the program
• Programs that run to completion with
predictable memory usage may leak without
causing problems
CSCE 121:509-512
Set 16: Vector and Free Store
25
Preventing Memory Leak:
Deallocation
• Use operator delete (for single object) or delete[]
(for multiple objects, i.e., array):
double* calc(int result_size, int max) {
int* p = new double[max];
double* result = new double[result_size];
// use p to calculate values to be put in result
delete[] p; // deallocates memory pointed to by p
return result;
}
// ...
double* r = calc(200,100);
// use r
delete[] r; // but this is easy to forget
CSCE 121:509-512
Set 16: Vector and Free Store
26
Another Memory Leak
void f() {
double* p = new double[27];
// ...
1st value
p = new double[42];
// ...
p:
delete[] p;
}
2nd value
// first array
// (of 27 doubles)
// leaked
CSCE 121:509-512
Set 16: Vector and Free Store
27
Preventing Memory Leaks More
Systematically
• One option is to have the run-time system, instead of
the programmer, find inaccessible memory and
return it to the free store
– called garbage collection
– some languages, including Java, have this
– C++ does not (efficiency issues)
• Another option, relevant to C++, is to avoid using new
and delete except in very constrained ways
– mostly rely on features, like vector, that do it for us
CSCE 121:509-512
Set 16: Vector and Free Store
28
Vector, Take 1, Leaks Memory
void f(int x) {
// constructor allocates x doubles on the
// free store
vector v(x);
// ... use v ...
}
// How can we give those x doubles back to
// the free store before f returns?
// v.elem is a private data member in vector
CSCE 121:509-512
Set 16: Vector and Free Store
29
Destructor
• C++ classes allow us to define a special
function, called a destructor
• Destructor is automatically called whenever a
variable of that class goes out of scope
– for example, when the function that defined the
variable is about to return
• The destructor code can do “clean up”
– most notably, it can delete any memory that has
been allocated on the free store
• Destructor for class T is denoted ~T()
CSCE 121:509-512
Set 16: Vector and Free Store
30
Vector, Take 1, Destructor
// a very simplified vector of doubles
class vector {
int sz;
double* elem;
public:
// constructor:
vector(int s) : sz(s) elem(new double[s]) { }
// ... get, set, size ...
// destructor:
~vector() { delete[] elem; }
};
CSCE 121:509-512
Set 16: Vector and Free Store
31
Important Resource Management
Technique
• Acquire resources in a constructor
• Release resources in the destructor
Examples of resources:
• memory
• files
• locks
• threads
• sockets
CSCE 121:509-512
Set 16: Vector and Free Store
32
Comparing Code Styles
Managing Memory Yourself
void f(int x) {
int* p = new int[x];
// ... use p ...
delete[] p;
}
Managing Memory in
Constructors and Destructors
void f(int x) {
vector v(x);
// ... use v ...
}
CSCE 121:509-512
Set 16: Vector and Free Store
33
Free Store Summary: Allocation
• Allocate using new (preferably in a constructor)
– new allocates an object on the free store,
sometimes initializes it, and returns a pointer to it
int* pi = new int;
// default initialization
// (none for int)
char* pc = new char(‘a’); // explicit
// initialization
double* pd = new double[10]; // allocation of
// (uninitialized) array
– new throws a bad_alloc exception if it cannot
allocate (out of memory)
CSCE 121:509-512
Set 16: Vector and Free Store
34
Free Store Summary: Deallocation
• Deallocate using delete and delete[]
(preferably in a destructor)
– delete and delete[] return the memory of any
object allocated by new to the free store for use in
future allocations
delete pi; // deallocate an individual object
delete[] pd; // deallocate an array of objects
– delete of a zero-valued pointer (“null pointer” or
nullptr) does nothing:
char* p = nullptr;
delete p; // harmless
CSCE 121:509-512
Set 16: Vector and Free Store
35
Allocating a Vector on the Stack vs.
Heap
Allocate Vector on Stack
vector v(5);
v.set(0,10);
cout << v.get(0);
v.set(1,40);
cout << v.get(1);
Allocate Vector on Heap
vector* pv = new vector(5);
(*pv).set(0,20);
cout << (*pv).get(0);
// Parentheses necessary!
// shorthand -> notation
pv->set(1,40);
cout << pv->get(1);
CSCE 121:509-512
Set 16: Vector and Free Store
36
Allocating a Vector on the Stack vs.
Heap
• The difference is where the “bookkeeping”
goes (sz and elem)
• In both cases, the array of objects pointed to
by elem is on the heap
• If vector is allocated on the stack (vector
v(5)), then sz and elem are on stack
• If vector is allocated on the heap (vector*
pv = new vector(5)), then sz and elem
are on the heap
CSCE 121:509-512
Set 16: Vector and Free Store
37
Deallocation of Vector Declared on
the Stack
• When vector variable goes out of scope:
– destructor is called automatically to deallocate the
array of elements
– the bookkeeping (sz and elem), which were on
the stack, will automatically be deallocated when
the stack frame for that scope is popped
• Safe! No memory leak
CSCE 121:509-512
Set 16: Vector and Free Store
38
Deallocation of Vector Declared on
the Heap
• When pointer variable goes out of scope:
– the space for the pointer is automatically
deallocated when the stack frame for that scope is
popped
• But you are responsible for deallocating the
bookkeeping (sz and elem) and the array!
• Note: destructor is automatically called when
delete is invoked on a pointer to an object of
that class
CSCE 121:509-512
Set 16: Vector and Free Store
39
Managing a Vector on the Stack vs.
Heap
Vector on Stack
void f() {
vector v(5);
v.set(0,10);
cout << v.get(0);
}
Vector on Heap
void f() {
vector* pv = new vector(5);
pv->set(0,10);
cout << pv->get(0);
delete pv;
}
// delete pv automatically calls
// destructor, which frees array,
// then delete frees sz and elem
CSCE 121:509-512
Set 16: Vector and Free Store
40
void*
• void* means “pointer to some memory
whose type is unknown to the compiler”
• Use void* to transmit an address between
pieces of code that do not know each other’s
types
– example: arguments of a callback function
• There are no objects of type void:
void v; // error
void f(); // f returns nothing; does not
// return an object of type void
CSCE 121:509-512
Set 16: Vector and Free Store
41
Assigning to void*
• Any pointer can be assigned to a void*
pointer:
int* pi = new int;
double* pd = new double[10];
void* pv1 = pi;
pv1 = pd;
CSCE 121:509-512
Set 16: Vector and Free Store
42
Using void*
• Most operations on pointers are forbidden on
void* pointers:
– cannot dereference, cannot subscript, cannot
increment, no implicit conversions
• Copying (assignment), however, is allowed
– that’s what it is for
• To use what a void* pointer points to, we
must explicitly tell the compiler what type of
object it points to, using static_cast
– use static_cast only when absolutely necessary!
CSCE 121:509-512
Set 16: Vector and Free Store
43
Code Examples with void*
void f(void* pv) {
void* pv2 = pv; // OK – copying
double* pd = pv; // error – implicit conversion
*pv = 7;
// error – dereference
pv[2] = 9;
// error – subscript
pv++;
// error – increment
int* pi = static_cast<int*>(pv); // OK –
// explicit conversion
// ... can access the memory via pi
}
CSCE 121:509-512
Set 16: Vector and Free Store
44
void* and FLTK Callbacks
• void* is the closest C++ has to a plain
machine address
• Some system facilities require a void*
• Remember FLTK callbacks? The parameters
were of type Address, which is just a
synonym for void*:
typedef void* Address;
void Lines_window::cb_next(Address,Address);
CSCE 121:509-512
Set 16: Vector and Free Store
45
Acknowledgments
• Photo on slide 1: by mekuria getinet, licensed
under CC BY2.0
• Core C++: A Software Engineering Approach,
Victor Shtern, Prentice Hall, 2000
• Slides are based on those for the textbook:
http://www.stroustrup.com/Programming/17_free_store.ppt
CSCE 121:509-512
Set 16: Vector and Free Store
46
Download