Chapter 18 - Chapter 18 Chapter Vectors and Arrays Bjarne Stroustrup Bjarne www.stroustrup.com/Programming www.stroustrup.com/Programming Abstract

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 18 Chapter Vectors and Arrays Bjarne Stroustrup Bjarne www.stroustrup.com/Programming www.stroustrup.com/Programming Abstract Abstract arrays, pointers, copy semantics, elements arrays, access, references access, Next lecture: parameterization of a type with a Next type (templates), and range checking (exceptions). (exceptions). Stroustrup/Programming 2 Overview Overview Vector revisited How are they implemented? Pointers and free store Destructors Copy constructor and copy assignment Arrays Array and pointer problems Changing size Templates Range checking and exceptions Stroustrup/Programming 3 Reminder Reminder Why look at the vector implementation? To see how the standard library vector really works To introduce basic concepts and language features To see how to directly deal with memory To see the techniques and concepts you need to understand C Free store (heap) Copying Dynamically growing data structures Including the dangerous ones To demonstrate class design techniques To see examples of “neat” code and good design Stroustrup/Programming 4 vector vector // a very simplified vector of doubles (as far as we got in chapter 17): // very double class vector { int sz; // the size // the double* elem; // pointer to elements // pointer public: vector(int s) :sz(s), elem(new double[s]) { } ~vector() { delete[ ] elem; } double get(int n) { return elem[n]; } double void set(int n, double v) { elem[n]=v; } int size() const { return sz; } // constructor // constructor // new allocates memory new // destructor // destructor // delete deallocates memory // deallocates // access: read access: // access: write // access: // the number of elements // the }; Stroustrup/Programming 5 A problem problem Copy doesn’t work as we would have hoped (expected?) void f(int n) { vector v(n); vector v2 = v; vector v3; vector v3 = v; v3 // define a vector // define // what happens here? what // what would we like to happen? // what // what happens here? // what // what would we like to happen? // what // … // } Ideally: v2 and v3 become copies of v (that is, = makes copies) and makes And all memory is returned to the free store upon exit from f() That’s what the standard vector does, does, but it’s not what happens for our still-too-simple vector Stroustrup/Programming 6 Naïve copy initialization (the default) Naïve void f(int n) { vector v1(n); vector v2 = v1; vector // initialization: initialization: // by default, a copy of a class copies its members // by // so sz and elem are copied // sz are } v1: v2: 3 3 Disaster when we leave f()! v1’s elements are deleted twice (by the destructor) Stroustrup/Programming 7 Naïve copy assignment (the default) Naïve void f(int n) { vector v1(n); vector v2(4); v2 = v1; // assignment : // assignment // by default, a copy of a class copies its members // by // so sz and elem are copied // sz are } v1: 3 2nd v2: 3 1st Disaster when we leave f()! v1’s elements are deleted twice (by the destructor) memory leak: v2’s elements are not deleted Stroustrup/Programming Stroustrup/Programming 8 Copy constructor (initialization) Copy class vector { int sz; double* elem; public: vector(const vector&) ; // … // }; // copy constructor: define copy // copy vector:: vector(const vector& a) :sz(a.sz), elem(new double[a.sz]) // allocate space for elements, then initialize them (by copying) // allocate { for (int i = 0; i<sz; ++i) elem[i] = a.elem[i]; } Stroustrup/Programming 9 Copy with copy constructor Copy void f(int n) { vector v1(n); vector v2 = v1; // copy using the copy constructor // copy // a for loop copies each value from v1 into v2 // for } v1: v2: 3 3 The destructor correctly deletes all elements (once only) Stroustrup/Programming 10 Copy assignment Copy class vector { int sz; double* elem; public: vector& operator=(const vector& a); // copy assignment: define copy // copy // … }; x=a; a: 8 1st x: 2nd 1 2 3 4 2 4 Memory leak? (no) 8 4 2 Operator = must copy a’s elements Stroustrup/Programming 11 Copy assignment Copy vector& vector::operator=(const vector& a) // like copy constructor, but we must deal with old elements // like // make a copy of a then replace the current sz and elem with a’s // sz elem { double* p = new double[a.sz]; // allocate new space // allocate for (int i = 0; i<a.sz; ++i) p[i] = a.elem[i]; // copy elements // copy delete[ ] elem; // deallocate old space // deallocate sz = a.sz; // set new size // set elem = p; // set new elements // set return *this; // return a self-reference return // return // The this pointer is explained in Lecture 19 The pointer // and in 17.10 } Stroustrup/Programming 12 Copy with copy assignment Copy void f(int n) { vector v1(n); vector v2(4); v2 = v1; } v1: // assignment // assignment 3 6 24 42 delete[ ]d by = No memory Leak v2: 1st 3 2nd 6 24 42 Stroustrup/Programming 13 Copy terminology Copy Shallow copy: copy only a pointer so that the two pointers Shallow now refer to the same object now What pointers and references do Deep copy: copy the pointer and also what it points to so that Deep the two pointers now each refer to a distinct object the What vector, string, etc. do What vector string Requires copy constructors and copy assignments for container classes Copy of x: x: Copy of x: x: y: y: Shallow copy Copy of y: Deep copy Stroustrup/Programming 14 Deep and shallow copy Deep v1: vector<int> v1; v1.push_back(2); v1.push_back(4); vector<int> v2 = v1; v2[0] = 3; int b = 9; int int& r1 = b; int& int& r2 = r1; r2 = 7; v2: 2 2 2 4 4 // deep copy (v2 gets its own copy of v1’s elements) // deep v1 // v1[0] is still 2 // is r2: r1: b: // shallow copy (r2 refers to the same variable as r1) // shallow r2 refers // b becomes 7 // becomes Stroustrup/Programming 15 Arrays Arrays Arrays don’t have to be on the free store char ac[7]; int max = 100; int ai[max]; // global array – “lives” forever – “in static storage” global int f(int n) { char lc[20]; // local array – “lives” until the end of scope – on stack char local int li[60]; double lx[n]; // error: a local array size must be known at compile time double error: // vector<double> lx(n); would work // vector<double> // … } Stroustrup/Programming 16 Address of: & Address You can get a pointer to any object not just to objects on the free store int a; char ac[20]; void f(int n) { int b; int* p = &b; p = &a; char* pc = ac; pc = &ac[0]; pc = &ac[n]; pc: p: a: ac: // pointer to individual variable // pointer // the name of an array names a pointer to its first element // the // equivalent to pc = ac equivalent // pointer to ac’s nth element (starting at 0th) pointer // warning: range is not checked warning: // … } Stroustrup/Programming 17 Arrays (often) convert to pointers Arrays void f(int pi[ ]) // equivalent to void f(int* pi) // equivalent { int a[ ] = { 1, 2, 3, 4 }; int b[ ] = a; // error: copy isn’t defined for arrays // error: b = pi; // error: copy isn’t defined for arrays. Think of a // error: // (non-argument) array name as an immutable pointer // (non-argument) pi = a; // ok: but it doesn’t copy: pi now points to a’s first element // pi // Is this a memory leak? (maybe) // Is int* p = a; // p points to the first element of a // int* q = pi; // q points to the first element of a // } pi: 1st 2nd a: 1 2 3 4 p: q: Stroustrup/Programming 18 Arrays don’t know their own size Arrays void f(int pi[ ], int n, char pc[ ]) void // equivalent to void f(int* pi, int n, char* pc) equivalent // warning: very dangerous code, for illustration only, warning: // never “hope” that sizes will always be correct // never { char buf1[200]; strcpy(buf1,pc); // copy characters from pc into buf1 pc buf1 // strcpy terminates when a '\0' character is found strcpy // hope that pc holds less than 200 characters pc strncpy(buf1,pc,200); // copy 200 characters from pc to buf1 pc buf1 // padded if necessary, but final '\0' not guaranteed padded int buf2[300]; // you can’t say char buf2[n]; n is a variable char if (300 < n) error("not enough space"); for (int i=0; i<n; ++i) buf2[i] = pi[i]; // hope that pi really has space for pi // n ints; it might have less // } Stroustrup/Programming 19 Be careful with arrays and pointers Be char* f() { char ch[20]; char* p = &ch[90]; // … // *p = 'a'; *p char* q; *q = 'b'; *q return &ch[10]; // we don’t know what this’ll overwrite // we // forgot to initialize // forgot // we don’t know what this’ll overwrite // we // oops: ch disappear upon return from f() // oops: disappear // (an infamous “dangling pointer”) (an } void g() { char* pp = f(); // … // *pp = 'c'; // we don’t know what this’ll overwrite *pp // we // (f’s ch are gone for good after the return from f) // Stroustrup/Programming } 20 Why bother with arrays? Why It’s all that C has It’s In particular, C does not have vectors There is a lot of C code “out there” There is a lot of C++ code in C style “out there” Here “a lot” means N*100M lines You’ll eventually encounter code full of arrays and pointers You’ll They represent primitive memory in C++ programs Here “a lot” means N*1B lines We need them (mostly on free store allocated by new) to implement We new to better container types better Avoid arrays whenever you can They are the largest single source of bugs in C and (unnecessarily) in They C++ programs C++ They are among the largest sources of security violations (usually They (avoidable) buffer overflows) (avoidable) Stroustrup/Programming 21 Types of memory Types vector glob(10); vector* some_fct(int n) { vector v(n); vector* p = new vector(n); vector* it it // … return p; } // global vector – “lives” forever // global “lives” // local vector – “lives” until the end of scope // “lives” // free-store vector – “lives” until we delete “lives” void f() { vector* pp = some_fct(17); // … // delete pp; // deallocate the free-store vector allocated in some_fct() // vector some_fct() } it’s easy to forget to delete free-store allocated objects Stroustrup/Programming so avoid new/delete when you can so new 22 Initialization syntax Initialization (array’s one advantage over vector) char ac[ ] = "Hello, world"; char // array of 13 chars, not 12 (the compiler // char // counts them and then adds a null // // character at the end character char* pc = "Howdy"; // pc points to an array of 6 chars char* // points char char* pp = {'H', 'o', 'w', 'd', 'y', 0 }; // another way of saying the same another int ai[ ] = { 1, 2, 3, 4, 5, 6 }; // array of 6 ints // array // not 7 – the “add a null character at the end” // not // rule is for literal character strings only rule int ai2[100] = { 0,1,2,3,4,5,6,7,8,9 }; // the last 90 elements are initialized to 0 int the double ad3[100] = { }; // all elements initialized to 0.0 // all Stroustrup/Programming 23 Vector (primitive access) (primitive // a very simplified vector of doubles: // very double vector v(10); for (int i=0; i<v.size(); ++i) { v.set(i,i); cout << v.get(i); } for (int i=0; i<v.size(); ++i) { for v[i]=i; cout << v[i]; } 10 0.0 1.0 // pretty ugly: // pretty // we’re used to this: // we’re 2.0 3.0 Stroustrup/Programming 4.0 5.0 6.0 7.0 8.0 9.0 24 Vector (we could use pointers for access) (we // a very simplified vector of doubles: // very double class vector { int sz; // the size // the double* elem; // pointer to elements // pointer public: vector(int s) :sz(s), elem(new double[s]) { } // constructor // constructor // … double* operator[ ](int n) { return &elem[n]; } // access: return pointer double* access: }; vector v(10); for (int i=0; i<v.size(); ++i) { // works, but still too ugly: // works, *v[i] = i; // means *(v[i]), that is return a pointer to // means // the ith element, and dereference it // the cout << *v[i]; } 10 0.0 1.0 2.0 3.0 Stroustrup/Programming 4.0 5.0 6.0 7.0 8.0 9.0 25 Vector (we use references for access) (we // a very simplified vector of doubles: // very double class vector { int sz; // the size // the double* elem; // pointer to elements // pointer public: vector(int s) :sz(s), elem(new double[s]) { } // constructor // constructor // … double& operator[ ](int n) { return elem[n]; } // access: return reference double& access: }; vector v(10); for (int i=0; i<v.size(); ++i) { // works and looks right! // works v[i] = i; // v[i] returns a reference to the ith element // returns cout << v[i]; } 10 0.0 1.0 2.0 3.0 Stroustrup/Programming 4.0 5.0 6.0 7.0 8.0 9.0 26 Pointer and reference Pointer You can think of a reference as an automatically dereferenced You immutable pointer, or as an alternative name for an object immutable Assignment to a pointer changes the pointer’s value Assignment to a reference changes the object referred to You cannot make a reference refer to a different object int a = 10; int* p = &a; // you need & to get a pointer // you *p = 7; // assign to a through p // // you need * (or [ ]) to get to what a pointer points to // you int x1 = *p; // read a through p // int& r = a; int& r = 9; int x2 = r; // r is a synonym for a // assign to a through r // // read a through r // p = &x1; r = &x1; // you can make a pointer point to a different object // you // error: you can’t change the value of a reference // error: Stroustrup/Programming 27 Next lecture Next We’ll see how we can change vector’s We’ll implementation to better allow for changes in the number of elements. Then we’ll modify vector to take elements of an arbitrary type and add range checking. That’ll imply looking at templates and revisiting exceptions. templates Stroustrup/Programming 28 ...
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