Chapter 17 - Chapter 17 Chapter vector and Free Store...

Info iconThis preview shows page 1. Sign up to view the full content.

View Full Document Right Arrow Icon
This is the end of the preview. Sign up to access the rest of the document.

Unformatted text preview: Chapter 17 Chapter vector and Free Store Bjarne Stroustrup Bjarne www.stroustrup.com/Programming www.stroustrup.com/Programming Abstract Abstract Vector is not just the most useful standard container, Vector it is also provides examples of some of the most important/powerful/ interesting implementation techniques. In this and the following lectures, we go through a series of increasingly sophisticated vector implementations, seeing classical problems related to use of memory and providing solutions. Here, we discuss free store (heap storage) management, and pointers. pointers. Stroustrup/Programming 2 Overview Overview Vector revisited How are they implemented? Pointers and free store Allocation (new) Access Access Arrays and subscripting: Dereferencing: * Deallocation (delete) Destructors Copy constructor and copy assignment Arrays Array and pointer problems Changing size Templates Range checking and exceptions Stroustrup/Programming 3 Vector Vector Vector is the most useful container Simple Compactly stores elements of a given type Efficient access Expands to hold any number of elements Optionally range-checked access How is that done? That is, how is vector implemented? We'll answer that gradually, feature after feature Vector is the default container prefer vector for storing elements unless there's a good prefer reason not to reason Stroustrup/Programming 4 Building from the ground up Building The hardware provides memory and addresses Low level Untyped Fixed-sized No checking As fast as the hardware architects can make it The application builder needs something like a vector Higher-level operations Type checked Size varies (as we get more data) Run-time checking Close-to optimally fast Stroustrup/Programming 5 Building from the ground up Building At the lowest level, close to the hardware, life’s simple and At brutal brutal We want to get to a higher level as quickly as we can You have to program everything yourself You have no type checking to help you Run-time errors are found when data is corrupted or the program crashes To become productive and reliable To use a language “fit for humans” Chapter 17-19 basically shows all the steps needed The alternative to understanding is to believe in “magic” The techniques for building vector are the ones underlying all higher-level The work with data structures work Stroustrup/Programming 6 Vector Vector A vector vector Can hold an arbitrary number of elements That number can vary over time Up to whatever physical memory and the operating system can Up handle handle E.g. by using push_back() E.g. push_back() Example vector<double> age(4); age[0]=.33; age[1]=22.0; age[2]=27.2; age[3]=54.2; age: 4 age[0]: age[1]: age[2]: age[3]: 0.33 22.0 27.2 54.2 Stroustrup/Programming 7 Vector Vector // a very simplified vector of doubles (like vector<double>): // very double (like vector<double> class vector { int sz; // the number of elements (“the size”) // the double* elem; // pointer to the first element // pointer public: vector(int s); // constructor: allocate s elements, // constructor: elements, // let elem point to them // let point // store s in sz // sz int size() const { return sz; } // the current size // the }; * means “pointer to” so double* is a “pointer to double” double* is double means What is a “pointer”? how do we make a pointer “point to” elements? How do we “allocate” elements? Stroustrup/Programming 8 Pointer values Pointer Pointer values are memory addresses 0 Think of them as a kind of integer values The first byte of memory is 0, the next 1, and so on 1 2 p2 *p2 2^20-1 7 A pointer points to an object of a given type E.g. a double* points to a double, not to a string E.g. double* double not string A pointer’s type determines how the memory referred to by pointer’s the pointer’s value is used the E.g. what a double* points to can be added not, say, concatenated E.g. double* Stroustrup/Programming 9 Vector (constructor) (constructor) vector::vector(int s) // vector's constructor // vector's :sz(s), // store the size s in sz // store in elem(new double[s]) // allocate s doubles on the free store elem(new // allocate // store a pointer to those doubles in elem // store in elem { } // Note: new does not initialize elements (but the standard vector does) // Note: does Free store: sz: 4 elem: A pointer new allocates memory from the free store and returns a pointer to the allocated memory Stroustrup/Programming 10 The computer’s memory The As a program sees it Local variables “lives on the stack” Global variables are “static data” The executable code are in “the code section” Stroustrup/Programming 11 The free store The (sometimes called "the heap") You request memory "to be allocated" "on the free store" by the new operator You new The new operator returns a pointer to the allocated memory The new A pointer is the address of the first byte of the memory For example int* p = new int; // allocate one uninitialized int // // int* means “pointer to int” // means int* q = new int[7]; // allocate seven uninitialized ints // allocate // “an array of 7 ints” // int double* pd = new double[n]; // allocate n uninitialized doubles // allocate double A pointer points to an object of its specified type A pointer does not know how many elements it points to pointer not p: q: Stroustrup/Programming 12 Access Access p1: p2: ??? 5 Individual elements int* p1 = new int; int* p2 = new int(5); int* // get (allocate) a new uninitialized int // // get a new int initialized to 5 // get int x = *p2; // get/read the value pointed to by p2 get/read // (or “get the contents of what p2 points to”) to”) // in this case, the integer 5 in int y = *p1; // undsefined: y gets an undefined value; don’t do that // Stroustrup/Programming 13 13 Access Access p3: 7 9 Arrays (sequences of elements) int* p3 = new int[5]; // get (allocate) 5 ints // int // array elements are numbered 0, 1, 2, … array p3[0] = 7; p3[1] = 9; // write to (“set”) the 1st element of p3 // write int x2 = p3[1]; // get the value of the 2nd element of p3 get int x3 = *p3; array array // we can also use the dereference operator * for an // *p3 means p3[0] (and vice versa) // *p3 Stroustrup/Programming 14 Why use free store? Why To allocate objects that have to outlive the function To that creates them: that For example double* make(int i) { return new double[i]; } Another example: vector's constructor Stroustrup/Programming 15 Pointer values Pointer Pointer values are memory addresses 0 Think of them as a kind of integer values The first byte of memory is 0, the next 1, and so on 1 2 p2 *p2 2^20-1 7 // you can see pointer value (but you rarely need/want to) : char* p1 = new char('c'); // allocate a char and initialize it to 'c' int* p2 = new int(7); // allocate an int and initialize it to 7 cout << "p1==" << p1 << " *p1==" << *p1 << "\n"; // p1==??? *p1==c cout << "p2==" << p2 << " *p2==" << *p2 << "\n"; // p2==??? *p2=7 Stroustrup/Programming 16 Access Access A pointer does not know the number of elements that pointer not it's pointing to (only the address of the first element) it's double* p1 = new double; *p1 = 7.3; // ok // ok p1: p1[0] = 8.2; // ok // ok p1[17] = 9.4; // ouch! Undetected error // ouch! p1[-4] = 2.4; // ouch! Another undetected error // ouch! double* p2 = new double[100]; p2: *p2 = 7.3; // ok // ok p2[17] = 9.4; // ok // ok p2[-4] = 2.4; // ouch! Undetected error // ouch! Stroustrup/Programming 8.2 7.3 7.3 17 Access Access A pointer does not know the number of elements that pointer not it's pointing to it's double* p1 = new double; double* p2 = new double[100]; p1: [0]: [99]: p2: p1[17] = 9.4; // error (obviously) error p1 = p2; p1 (after the assignment) // assign the value of p2 to p1 p2 p1 p1: p1[17] = 9.4; // now ok: p1 now points to the array of 100 doubles p1 doubles Stroustrup/Programming 18 Access Access A pointer does know the type of the object that it's pointer does pointing to pointing int* pi1 = new int(7); int* pi2 = pi1; // ok: pi2 points to the same object as pi1 // ok: points double* pd = pi1; // error: can't assign an int* to a double* // error: to char* pc = pi1; // error: can't assign an int* to a char* // error: to There are no implicit conversions between a pointer to one value There type to a pointer to another value type type However, there are implicit conversions between value types: pc: pi1: *pc = 8; // ok: we can assign an int to a char // ok: to *pc = *pi1; // ok: we can assign an int to a char // ok: to 7 7 Stroustrup/Programming 19 Pointers, arrays, and vector Pointers, Note With pointers and arrays we are "touching" hardware With directly with only the most minimal help from the language. Here is where serious programming errors can most easily be made, resulting in malfunctioning programs and obscure bugs and Be careful and operate at this level only when you really need to vector is one way of getting almost all of the flexibility and vector performance of arrays with greater support from the language (read: fewer bugs and less debug time). language Stroustrup/Programming 20 Vector (construction and primitive access) (construction // a very simplified vector of doubles: // very double class vector { int sz; // the size // the double* elem; // a pointer to the elements // pointer public: vector(int s) :sz(s), elem(new double[s]) { } // constructor // constructor double get(int n) { return elem[n]; } // access: read double access: void set(int n, double v) { elem[n]=v; } // access: write access: int size() const { return sz; } // the current size // the }; vector v(10); for (int i=0; i<v.size(); ++i) { v.set(i,i); cout << v.get(i) << ' '; } 10 0.0 1.0 2.0 3.0 4.0 Stroustrup/Programming 5.0 6.0 7.0 8.0 9.0 21 A problem: memory leak problem: double* calc(int result_size, int max) { double* p = new double[max]; // allocate another max doubles // allocate // i.e., get max doubles from the free store max double* result = new double[result_size]; // … use p to calculate results to be put in result … // use to return result; } double* r = calc(200,100); // oops! We “forgot” to give the memory // // allocated for p back to the free store // allocated Lack of de-allocation (usually called "memory leaks") can be a Lack serious problem in real-world programs serious A program that must run for a long time can't afford any program memory leaks memory Stroustrup/Programming 22 A problem: memory leak problem: double* calc(int result_size, int max) { int* p = new double[max]; // allocate another max doubles int* allocate // i.e., get max doubles from the free store max double* result = new double[result_size]; // … use p to calculate results to be put in result … // use to delete[ ] p; // de-allocate (free) that array // de-allocate // i.e., give the array back to the free store return result; } double* r = calc(200,100); // use r // use delete[ ] r; // easy to forget easy Stroustrup/Programming 23 Memory leaks Memory A program that needs to run "forever" can't afford any memory leaks An operating system is an example of a program that "runs forever" If a function leaks 8 bytes every time it is called, how many days can it If run before it has leaked/lost a megabyte? run Trick question: not enough data to answer, but about 130,000 calls All memory is returned to the system at the end of the program If you run using an operating system (Windows, Unix, whatever) Program that runs to completion with predictable memory usage may Program leak without causing problems leak i.e., memory leaks aren't "good/bad" but they can be a problem in specific circumstances specific Stroustrup/Programming 24 Memory leaks Memory Another way to get a Another memory leak memory p: void f() { double* p = new double[27]; // … // p = new double[42]; // … // delete p; } 1st value 2nd value // 1st array (of 27 doubles) leaked // Stroustrup/Programming 25 Memory leaks Memory How do we systematically and simply avoid memory How leaks? leaks? don't mess directly with new and delete don't delete Use vector, etc. Use vector Or use a garbage collector A garbage collector is a program the keeps track of all of your garbage allocations and returns unused free-store allocated memory to the free store (not covered in this course; see http://www.research.att.com/~bs/C++.html) http://www.research.att.com/~bs/C++.html) Unfortunately, even a garbage collector doesn’t prevent all leaks See also Chapter 25 Stroustrup/Programming 26 A problem: memory leak problem: void f(int x) { vector v(x); // define a vector // define // (which allocates x doubles on the free store) double // … use v … // use // give the memory allocated by v back to the free store // back // but how? (vector''s elem data member is private) s elem // but } Stroustrup/Programming 27 Vector (destructor) (destructor) // a very simplified vector of doubles: // very double class vector { int sz; // the size // the double* elem; // a pointer to the elements // pointer public: vector(int s) // constructor: allocates/acquires memory vector(int constructor: :sz(s), elem(new double[s]) { } :sz(s), ~vector() // destructor: de-allocates/releases memory ~vector() // destructor: { delete[ ] elem; } // … // }; Note: this is an example of a general and important technique: acquire resources in a constructor release them in the destructor Examples of resources: memory, files, locks, threads, sockets Examples Stroustrup/Programming 28 28 A problem: memory leak problem: void f(int x) { int* p = new int[x]; // allocate x ints // int vector v(x); // define a vector (which allocates another x ints) // define (which ints) // … use p and v … // use and delete[ ] p; // deallocate the array pointed to by p // deallocate // the memory allocated by v is implicitly deleted here by vector's destructor // the is } The delete now looks verbose and ugly The now How do we avoid forgetting to delete[ ] p? How delete[ Experience shows that we often forget Prefer deletes in destructors Prefer delete Stroustrup/Programming 29 Free store summary Free Allocate using new Allocate new New allocates an object on the free store, sometimes initializes it, and New returns a pointer to it returns int* pi = new int; char* pc = new char('a'); double* pd = new double[10]; // default initialization (none for int) int // explicit initialization explicit // allocation of (uninitialized) array allocation New throws a bad_alloc exception if it can't allocate New bad_alloc Deallocate using delete and delete[ ] Deallocate delete delete[ delete and delete[ ] return the memory of an object allocated by new to delete[ new the free store so that the free store can use it for new allocations the delete pi; delete pc; delete[ ] pd; // deallocate an individual object deallocate // deallocate an individual object deallocate // deallocate an array deallocate Delete of a zero-valued pointer ("the null pointer") does nothing char* p = 0; delete p; // harmless harmless Stroustrup/Programming 30 void* void* void* means "pointer to some memory that the compiler doesn't know the type of" know We use void* when we want to transmit an address between We void* pieces of code that really don't know each other's types – so the programmer has to know programmer There are no objects of type void There void Example: the arguments of a callback function void v; // error error void f(); // f() returns nothing – f() does not return an object of type void not void Any pointer to object can be assigned to a void* Any void* int* pi = new int; double* pd = new double[10]; void* pv1 = pi; void* pv2 = pd; Stroustrup/Programming 31 void* void* To use a void* we must tell the compiler what it points to we void f(void* pv) { void* pv2 = pv; // copying is ok (copying is what void*s are for) // copying double* pd = pv; // error: cannot convert void* to double* // error: *pv = 7; // error: you can’t dereference a void* // error: // good! The int 7 is not represented like the double 7.0) pv[2] = 9; // error: you can’s subscript a void* // error: pv++; // error: you can’t increment a void* error: int* pi = static_cast<int*>(pv); // ok: explicit conversion // // … } A static_cast can be used to explicitly convert to a pointer to static_cast object type object "static_cast" is a deliberately ugly name for an ugly (and dangerous) is operation – use it only when absolutely necessary operation Stroustrup/Programming 32 void* void* void* is the closest C++ has to a plain machine address Some system facilities require a void* Some void* Remember FLTK callbacks? Address is a void*: void* typedef void* Address; void Lines_window::cb_next(Address,Address) Stroustrup/Programming 33 Pointers and references Pointers Think of a reference as an automatically dereferenced Think pointer pointer Or as “an alternative name for an object” A reference must be initialized The value of a reference cannot be changed after The initialization initialization int x = 7; int y = 8; int* p = &x; *p = 9; p = &y; // ok // ok int& r = x; x = 10; r = &y; // error (and so is all other attempts to change what r refers to) // error Stroustrup/Programming 34 Next lecture Next The next lecture discusses copying and arrays Stroustrup/Programming 35 ...
View Full Document

This note was uploaded on 02/18/2012 for the course CSCE 121 taught by Professor Walter daugherity during the Fall '09 term at Texas A&M.

Ask a homework question - tutors are online