Download presentation
Presentation is loading. Please wait.
Published byJack Lewis Modified over 9 years ago
1
CSCE 121-200 Introduction to Program Design and Concepts J. Michael Moore Spring 2015 Set 17: Vectors and Arrays 1 Based on slides created by Bjarne Stroustrup and Jennifer Welch
2
CSCE 121:509-512 Set 16: Vectors and Arrays Vector, Take 1, Revisited class vector { int sz; double* elem; public: vector(int s) : sz{s}, elem{ new double[s] } { } ~vector() { delete[] elem; } double get(int n) { return elem[n]; } void set(int n, double v) { elem[n] = v; } int size() const { return sz; } }; 2
3
CSCE 121:509-512 Set 16: Vectors and Arrays Problem with One-Argument Constructors A constructor with a single argument defines an implicit conversion from the argument type to the constructor’s type Since our vector’s constructor takes an int as an argument, we get an implicit conversion from int to vector: vector v1 = 7; // v1 has 7 elements, each with value 0 and void f(vector v) { /*... */ } /*... */ f(7); // calls f() with a vector of 7 elements This is usually not what we want! Very error-prone 3
4
CSCE 121:509-512 Set 16: Vectors and Arrays Explicit Constructors To avoid such unwanted implicit conversions, declare one-argument constructors as explicit: class vector { //... public: explicit vector(int s); //... }; Now we get a compile-time error with vector v1 = 7; and f(7); 4
5
CSCE 121:509-512 Set 16: Vectors and Arrays Copying Vector void f(int n) { vector v(n); vector v2 = v; // What happens? // What do we want to happen? vector v3; v3 = v; // What happens? // What do we want to happen? //... } Standard vector makes copies of v in both these cases, and all memory is returned to the free store when f returns How can we make sure this happens? 5
6
CSCE 121:509-512 Set 16: Vectors and Arrays Default Copying Problem #1 The language default is that assignment causes all the data members to be copied But the data pointed to by pointers is not copied! Disaster when f returns, as v1’s elements are deleted twice (by the destructor) void f(int n) { vector v1(n); vector v2 = v1; } 6 3 3 v1: v2:
7
CSCE 121:509-512 Set 16: Vectors and Arrays Default Copying Problem #2 Disaster when f returns, as v1’s elements are deleted twice (by the destructor) And, there is a memory leak: v2’s elements are not deleted void f(int n) { vector v1(n); vector v2(4); v2 = v1; } 7 3 4 3 v1: v2: 2 nd 1 st
8
CSCE 121:509-512 Set 16: Vectors and Arrays Copying To avoid these problems, we have to write our own code for – copy constructor: what should happen when a new vector is declared using a pre-existing one – copy assignment: what should happen when we assign one (pre-existing) vector to another (pre- existing) vector We have to make sure that the data in the array is copied, not just the pointer to the array, and we have to make sure there is no memory leak 8
9
CSCE 121:509-512 Set 16: Vectors and Arrays Copy Constructor We make an additional constructor for vector, which takes as an argument another vector vector(const vector& a) : sz{a.sz}, elem { new double[a.sz] } { // copy data from a into newly allocated space for (int i = 0; i < sz; ++i) elem[i] = a.elem[i]; } Now the code vector v2 = v; will initialize v2 by calling vector’s copy constructor with v as its argument. 9
10
CSCE 121:509-512 Set 16: Vectors and Arrays Copy with Copy Constructor void f(int n) { vector v1(n); vector v2 = v1; } The destructor correctly deletes all elements when f returns (once for each vector) 10 3 3 v1: v2:
11
CSCE 121:509-512 Set 16: Vectors and Arrays Should the Copy Constructor be Explicit? Not if we want the syntax “ vector v2 = v1 ” to work; in this case we want the implicit conversion from one vector to another Also, if the copy constructor were explicit, we would not be able to pass a vector by value If the copy constructor were made explicit, then we would have to use this syntax to make a vector by copying from another vector: vector v2(v1); // call the constructor that // takes a vector argument 11
12
CSCE 121:509-512 Set 16: Vectors and Arrays Copy Assignment For assigning to a pre-existing vector, we must overload the assignment operator = to do the right thing 12 vector& operator=(const vector& a) { // allocate new space and copy a’s elements to it: double* p = new double[a.sz]; for (int i = 0; i < a.sz; ++i) [i] = a.elem[i]; delete[] elem; // deallocate old space sz = a.sz; // set new size elem = p; // set pointer to new elements return *this; // return a self-reference } In every member function, the identifier this is a pointer that points to the object for which the member function was called
13
CSCE 121:509-512 Set 16: Vectors and Arrays Copy with Copy Assignment void f(int n) { vector v1; // pushback 6, 24 and 42 vector v2(4); v2 = v1; } 13 364224 4 3 v1: v2: 2 nd 1 st 42246 delete[ ]d by = No memory Leak
14
CSCE 121:509-512 Set 16: Vectors and Arrays Shallow vs. Deep Copy Shallow copy: copies only a pointer; the two pointers now refer to the same object – Examples: pointers, references Deep copy: also copy what the pointer points to; the two pointers now refer to distinct objects – Examples: vector, string,… – Requires copy constructors and copy assignments for container classes – Must copy “all the way down” if there are more levels in the object 14 x: y: Copy of y: y: Copy of x: x:Copy of x: Shallow copyDeep copy
15
CSCE 121:509-512 Set 16: Vectors and Arrays Deep Copy vector v1 {2,4}; vector v2 = v1; v2[0] = 3; Shallow Copy int b = 9; int& r1 = b; int& r2 = r1; r2 = 7; 15 4 v1: 2 24 2 3 v2: 2 9 7 r1:r2:b: Shallow vs. Deep Copy Examples
16
CSCE 121:509-512 Set 16: Vectors and Arrays Move Constructor and Move Assignment Thanks to innovations on C++11, these functions can be provided to move (instead of copy) – speeds up performance by avoiding unnecessary copying We will not cover them, however – read the texbook and see textbook slides if you are interested 16
17
CSCE 121:509-512 Set 16: Vectors and Arrays Essential Operations Constructors – with argument(s): to initialize the object as we wish, perhaps establish some invariant – with no arguments (default constructor): needed if we want to make objects of the class without specifying an initializer, e.g., to put objects into a vector (“ vector vi(10); ”) Destructor: needed if the class acquires resources (e.g., memory on the free store); might be needed if it has a pointer/reference member – base class should have a virtual destructor Copy constructor and copy assignment: needed if the class has a destructor; if an object has acquired a resource then usually deep copy is needed Move constructor and move assignment: needed if the class has a destructor; deep copy can be expensive 17
18
CSCE 121:509-512 Set 16: Vectors and Arrays Arrays Arrays don’t have to be on the free store: char ac[7]; // global array, in static storage, // lives “forever” int max = 100; int ai[max]; // another global array int f(int n) { char lc[20]; // local array, on stack, // lives until end of scope int li[60]; // another local array double lx[n]; // error! size of a local array // must be known at compile time } 18
19
CSCE 121:509-512 Set 16: Vectors and Arrays Recall Address-of Operator & You can get a pointer to any object, not just those on the free store int a; char ac[20]; void f(int n) { int b; int* p = &b; p = &a; char* pc = ac; // array name is a pointer to first element pc = &ac[0]; // equivalent to pc = ac pc = &ac[n]; // pointer to ac’s n-th element // Warning! No range checking } 19
20
CSCE 121:509-512 Set 16: Vectors and Arrays Arrays (Often) Convert to Pointers void f(int pi[]) // same as void f(int* pi) { int a[] = { 1, 2, 3, 4 }; int b[] = a; // error! copy (constructor) isn’t defined for arrays b = pi; // error! copy (assignment) isn’t defined for arrays pi = a; // OK but doesn’t copy; pi points to a’s first element; // is this a memory leak? Maybe int* p = a; // p points to a’s first element int* q = pi; // q points to a’s first element } 20 1 pi: a: 234 p: 1 st 2 nd q:
21
CSCE 121:509-512 Set 16: Vectors and Arrays Arrays Don’t Know Their Own Size void f(int pi[], int n, char pc[]) // same as void f(int* pi, int n, char* pc) // Warning! Very dangerous code. Do not emulate! Never // “hope” that sizes will be correct { char buf1[200]; strcpy(buf1,pc); // copy chars from pc into buf1; strcpy // stops when a ‘\0’ char is found; // hope that pc holds < 200 chars strncpy(buf1,pc,200); // copy 200 chars from pc to buf1, // padded if necessary, but final // ‘\0’ is not guaranteed int buf2[300]; // can’t say int buf2[n] since n is a variable if (300 < n) error(“not enough space”); for (int i = 0; i < n; ++i) buf2[i] = pi[i]; // hope that pi has // space for n ints } 21
22
CSCE 121:509-512 Set 16: Vectors and Arrays Array and Pointer Pitfalls char* f() { char ch[20]; char* p = &ch[90]; //... *p = ‘a’; // we don’t know what this will overwrite char* q; // forgot to initialize *q = ‘b’; // we don’t know what this will overwrite return &ch[10]; // Oops! ch disappears upon return // from f(); an infamous “dangling pointer” } void g() { char* pp = f(); //... *pp = ‘c’; // we don’t know what this will overwrite; // f’s ch is gone after f’s return } 22
23
CSCE 121:509-512 Set 16: Vectors and Arrays So Why Bother with Arrays? They are all that C has – lots of C code “out there” (billions of lines) – lots of C++ code in C style (hundreds of millions of line) – You’ll eventually encounter code full of arrays and pointers They represent primitive memory in C++ programs – we need them (mostly on free store allocated by new) to implement better container types, like vector Avoid arrays whenever you can – largest single source of bugs in C and (unnecessarily) in C++ programs – among the largest sources of security violations, usually (avoidable) buffer overflows 23
24
CSCE 121:509-512 Set 16: Vectors and Arrays Accessing Elements in Our Vector So far, we are using member functions set and get: for (int i = 0; i < v.size(); ++i) { v.set(i,i); cout << v.get(i); } But we would prefer to use square brackets: for (int i = 0; i < v.size(); ++i) { v[i] = i; cout << v[i]; } How can we do that? 24 1.02.03.04.05.06.07.08.00.09.010
25
CSCE 121:509-512 Set 16: Vectors and Arrays Using Pointers for Accessing Vector Elements We can override the [] operator inside the vector class: double* operator[](int n) // return pointer to n-th element of elem array { return &elem[n]; // return address } But we need to use the dereference operation *: for (int i = 0; i < v.size(); ++i) { *v[i] = i; cout << *v[i] } Still not what we want 25
26
CSCE 121:509-512 Set 16: Vectors and Arrays Using References for Accessing Vector Elements We can override the [] operator inside the vector class like this: double& operator[](int n) // return reference to n-th element of elem array { return elem[n]; // return reference } Now we get what we want (no need to use dereference operator * since references are automatically dereferenced): for (int i = 0; i < v.size(); ++i) { v[i] = i; cout << v[i] } 26
27
CSCE 121:509-512 Set 16: Vectors and Arrays Acknowledgments Photo on title slide: Repetition by elPadawan, license CC BY-SA 2.0Repetition elPadawanCC BY-SA 2.0 Slides are based on those for the textbook: http://www.stroustrup.com/Programming/18_arrays.ppt 27
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.