Presentation is loading. Please wait.

Presentation is loading. Please wait.

Dynamic Array Objects CS 1037 Fundamentals of Computer Science II TexPoint fonts used in EMF. Read the TexPoint manual before you delete this box.: A AA.

Similar presentations


Presentation on theme: "Dynamic Array Objects CS 1037 Fundamentals of Computer Science II TexPoint fonts used in EMF. Read the TexPoint manual before you delete this box.: A AA."— Presentation transcript:

1 Dynamic Array Objects CS 1037 Fundamentals of Computer Science II TexPoint fonts used in EMF. Read the TexPoint manual before you delete this box.: A AA A A A A

2 A Smarter Dynamic Array Built-in dynamic array new[] very limited – manual insert/erase/resize is hard – must remember each array’s size in separate variable – must remember to delete[] each array – no range checking, so bugs very hard to find Want something more like this: 2 dynarray_of_int primes(3); // start with 3 items primes[0] = 2; // set item, like an array primes[1] = 3; primes[2] = 5; primes.push_back(7); // add 4th item, so {2,3,5,7} primes.erase(2); // remove 3rd item, {2,3,7}

3 Why C/C++ Arrays So Stupid? Performance: most light-weight array possible; this can matter, but rarely Simplicity: no interface, no objects Philosophical: language should provide basic building blocks; everything else should be a ‘library’ (e.g. the entire STL) – What is built-in to Python/C# is ‘library’ in C++ 3

4 A Unifying Concept 4 dynarray soundwavestring bookmarks polygon deck_of_cards... vertices chart_seriesedges

5 Interface Version 1 5 class dynarray_of_double { public: dynarray_of_double(); // start empty dynarray_of_double(int size); // start as non-empty int size(); // returns current size void push_back(double item); // appends an item void erase(int index); // erases an item void clear(); // resets to empty array double& operator[](int index); // returns item[index] // boring details (copy constructor etc.) ~ dynarray_of_double(); dynarray_of_double(const dynarray_of_double& src); void operator=(const dynarray_of_double& src);... }; (for type double )

6 Exact-Size Representation 6 class dynarray_of_double {... private: int m_size; // number of items in array double* m_items; // pointer to array data }; primes 3 size items dynarray_of_double primes; primes.push_back(2.0); // add first item primes.push_back(3.0); // add second item primes.push_back(5.0); // add third item (for type double )

7 Exact-Size Representation Works fine, but ‘slow’ to add many items. Why? 7 void dynarray_of_double::push_back(double item) { // allocate array that is 1 slot bigger double* new_items = new double[m_size+1]; for (int i = 0; i < m_size; ++i) new_items[i] = m_items[i]; delete[] m_items; m_items = new_items; // copy the new item to the last slot of our new array m_items[m_size] = item; m_size++; }

8 Exact-Size Would Be Slow Suppose size = n ¡ 1. How much work does push_back do to make size n ? How much work to build list of n items? 8 copy item new, delete, size++ really slow for large n

9 Realistic dynarray Representation 9 class dynarray_of_double {... int m_size; // official number of items added int m_capacity; // actual number of slots reserved double* m_items; // pointer to array data }; primes 3 size capacity ???? 4 items dynarray_of_double primes; primes.push_back(2.0); // add first item primes.push_back(3.0); // add second item primes.push_back(5.0); // add third item (for type double )

10 Motivation for capacity Advantage: performance 1.Appending n items takes ¼ n steps total (good!) Without capacity, takes ¼ n 2 steps (too slow!) Disadvantages: 1.Wasted space when capacity > size 2. sizeof(dynarray) becomes larger 3.Harder to implement (especially array-of-objects) 10 We will prove this

11 Exercise in Visual Studio See snippets #1 and #2 11

12 Real Life™ Example Example from Chrome source code 12 // The cookie monster is the system for storing // and retrieving cookies. class CookieMonster: public CookieStore { public:... typedef std::vector CookieList; // Returns all the cookies CookieList GetAllCookiesForURL(const GURL& url); std::vector is C++ standard version of dynarray

13 Real Life™ Example From UWO research code, defines a graph 13 struct graph_edge { var_t p,q; // edge goes from vertex p to vertex q cost_t w; // edge weight }; struct energy_defn { varcount_t varcount; // number of variables labelcount_t labelcount; std::vector edges;... }; {1,0,20}, {1,2,15}

14 operator[](int) Saw this used in A2 vec3 class: 14 class vec3 {... double& operator[](int index);... double m_elem[3]; // three elements }; double& vec3::operator[](int index) { return m_elem[index]; // reference to one element } void main() { vec3 v; v[0] = 5.0; // set 'x' element to 5.0 }

15 operator[](int) Works same for dynarray 15 class dynarray_of_double {... double& operator[](int index);... double* m_items; // pointer to items }; double& dynarray_of_double::operator[](int index) { return m_items[index]; // reference to one item } void main() { dynarray_of_double samples; samples[0] = 5.0; // set first sample to 5.0 } (for type double )

16 Topics for dynarray We will touch some topics in context of dynarray over next few lectures: 1.Assertions (range checking) 2.More functionality ( insert, pop_back ) 3.Complexity Analysis (just basics) 4.Arrays-of-objects (advanced C++) 5.Templates (next major topic) 16

17 Range Checking C/C++ arrays let you “shoot self in foot” Range checking is huge help finding bugs! operator[] gives us chance to check Such code called a “sanity check” 17 double* samples = new double[n]; for (int i = 0; i <= n; ++i) // nasty bug that quietly samples[i] = 0.0; // messes up memory! double& dynarray_of_double::operator[](int index) { if (index = m_size) // check for bug report_error_message(); // notify programmer! return m_items[index]; }

18 Sanity Checks – Assertions Formal way to express assumption of code that follows. ( “assert BLAH is true”) If BLAH == false, program will terminate! 18 #include // defines assert() double square_root(double x) { assert(x >= 0); // check that x >= 0... } y = square_root(-1.0); // assumption violated! (-1 >= 0) == false

19 Sanity Checks – Assertions For arrays, operator[] assumes index within range [0..size), so assert it! Buggy code now generates run-time error: 19 double& dynarray_of_double::operator[](int index) { assert(index >= 0 && index < m_size); // range check return m_items[index]; // index is OK! } dynarray_of_double samples(n); for (int i = 0; i <= n; ++i) samples[i] = 0.0; // bug detected!!

20 Assertion Examples 20 double min_value(double* values, int count) { assert(count > 0); // not well-defined for count==0... double arcsin(double x) { assert(x >= -1.0 && x <= 1.0); // defined for [-1,1]... rectangle::rectangle(int t, int l, int wd, int ht) { assert(wd >= 0); // width cannot be negative assert(ht >= 0); // height cannot be negative... void dynarray_of_double::erase(int index) { assert(index >= 0 && index < m_size); // range check...

21 dynarray::push_back 21 void dynarray_of_double::push_back(double item) { if (m_size == m_capacity) // check if array is full grow_capacity(); // reserve at least one slot m_items[m_size] = item; // copy to next available slot ++m_size; } class dynarray_of_double {... private: void grow_capacity(); // internal member function... }; Put “grow the array” code in a separate function; makes push_back easier (for type double )

22 dynarray::push_back 22 void dynarray_of_double::grow_capacity() { if (m_capacity == 0) // choose a larger capacity m_capacity = 1; else m_capacity = m_capacity*2; // double the capacity! // create bigger array and copy old items double* new_items = new double[m_capacity]; for (int i = 0; i < m_size; ++i) new_items[i] = m_items[i]; // copy old items delete[] m_items; // delete old array m_items = new_items; // point at new array } (for type double )

23 dynarray::erase 23 void dynarray_of_double::erase(int index) { assert(index >= 0 && index < m_size); for (int i = index; i < m_size-1; ++i) m_items[i] = m_items[i+1]; // copy from next slot m_size--; } (for type double ) primes.erase(1); // erase second item primes 3 size capacity ???? 4 items before: primes ???? 4 after erase:

24 dynarray_of_point Just change of item type class dynarray_of_point { public:... void push_back(point item); // double --> point void erase(int index); void clear(); point& operator[](int index); // double --> point... private: int m_size; int m_capacity; point* m_items; // double --> point };

25 dynarray_of_point 25 void dynarray_of_point::grow_capacity() { if (m_capacity == 0) m_capacity = 1; else m_capacity = m_capacity*2; point* new_items = new point[m_capacity]; for (int i = 0; i < m_size; ++i) new_items[i] = m_items[i]; delete[] m_items; m_items = new_items; } Just change of item type...

26 dynarray_of_point Access (x,y) just like for built-in arrays 26 point p(10,20); point q(15,30); dynarray_of_point polygon(3); polygon[0] = p; // set 1st point polygon[1] = q; // set 2nd point polygon[2].x = p.x; // set 3rd point's x component polygon[2].y = q.y; // set 3rd point's y component polygon 3 size capacity items xy

27 Exercise in Visual Studio See snippet #3 27

28 dynarray of Pointers Motivation: Recall “array of arrays” example (from Review) 28 double** tracks = new double*[num_tracks]; // array of for (int i = 0; i < num_tracks; ++i) // sound tracks[i] = new double[num_samples]; // patterns tracks ???? stack heap... ????... ????...

29 dynarray_of_doubleptr Again, just change of item type class dynarray_of_doubleptr { public:... void push_back(double* item); // double --> double* void erase(int index); void clear(); double*& operator[](int index); // double --> double*... private: int m_size; int m_capacity; double** m_items; // double --> double* };

30 Again, just change of item type... dynarray_of_doubleptr 30 void dynarray_of_doubleptr::grow_capacity() { if (m_capacity == 0) m_capacity = 1; else m_capacity = m_capacity*2; double** new_items = new double*[m_capacity]; for (int i = 0; i < m_size; ++i) new_items[i] = m_items[i]; delete[] m_items; m_items = new_items; }

31 dynarray_of_doubleptr Each item is a double* variable 31 double* piano = new double[1000]; // array of samples double* brass = new double[1000]; // array of samples dynarray_of_doubleptr tracks; tracks.push_back(piano); // add track for piano tracks.push_back(brass); // add track for trumpet etc. tracks 2 size cap 2 items brass piano

32 dynarray_of_doubleptr Each item is a double* variable 32 double* samples = tracks[0]; // copy ptr to 1st track samples[0] = 5.0; // 1st track, 1st sample tracks[1][0] = 7.0; // 2nd track, 1st sample tracks 2 size cap 2 items samples

33 Exercise in Visual Studio See snippet #4 33

34 Interface Version bool empty(); // test if size==0 void resize(int new_size); // set official size void reserve(int capacity); // pre-allocate capacity void insert(int index, double item); // insert copy of void erase(int index); // item at 'index' void push_back(double item); void pop_back(); // erase last item void push_front(double item); // prepend copy of item void pop_front(); // erase first item double& front(); // shorthand for items[0] double& back(); // shorthand for items[size-1] Add more functionality... dynarray version 2

35 dynarray::insert 35 // inserts item at specified index; items in // range [index..size) will be moved upwards by 1 slot void insert(int index, double item); primes.insert(1,3.0); // insert 3.0 into 2nd slot primes 3 size capacity ???? 4 items before: primes after insert: dynarray version 2

36 dynarray::insert 36 void dynarray_of_double::insert(int index, double item) { assert(index >= 0 && index <= m_size); if (m_size == m_capacity) // reserve space if needed grow_capacity(); // move items that follow 'index' to a higher slot for (int i = m_size; i > index; --i) m_items[i] = m_items[i-1]; m_items[index] = item; // copy item to requested index ++m_size; } dynarray version 2

37 Other Functionality is Easy! 37 void dynarray_of_double::push_back(double item) { insert(m_size,item); // push_back can now call insert! } void dynarray_of_double::pop_back() { erase(m_size-1); } void dynarray_of_double::push_front(double item) { insert(0,item); } void dynarray_of_double::pop_front() { erase(0); } double& dynarray_of_double::back() { assert(m_size > 0); return m_items[m_size-1]; } dynarray version 2

38 Exercise in Visual Studio See snippet #5 38

39 Suppose size = n ¡ 1. How much work does push_back do to make size n ? How much work to build list of n items? Rough Complexity Analysis 39 much faster than n 2 !

40 Suppose size = n ¡ 1. How much work does push_front do to make size n ? How much work to build list of n items? Rough Complexity Analysis 40 very slow for large n

41 dynarray of Objects Recall our simple string object hi 5 'h''e''l' 'o'0 main globals call stack 'h''e''l' 'o'0 heap sizechars empty 00 void main() { string hi("hello"); // copy of "hello" string empty; // empty string (null-terminated) } dynarray version 2

42 dynarray of Objects 42 names 2 'L''i''a''m'0 main globals call stackheap void main() { dynarray_of_string names; names.push_back("Liam"); names.push_back("Elora"); } 'E''l''o''r''a'0 2 sizecapitems 4 sizechars 5 'L''i''a''m'0 'E''l''o''r''a'0 dynarray version 2

43 dynarray of Objects How many string objects should exist? How many do exist? 43 void main() { dynarray_of_string copies; copies.push_back("test"); } copies 3 't''e''s''t'0 main globals 4 sizecapitems 4 sizechars 't''e''s''t'0 'e''s''t'0 'e''s''t'0 0 Four! extra string object! dynarray version 2

44 dynarray of Objects So... is it OK to create >size objects? Some extra objects seem harmless... – int, double, string, point, double* Some extra objects not acceptable... – objects with side-effects in constructor/destructor – objects with no default-constructor (won’t compile) Poor design: breaks encapsulation! – capacity is internal implementation detail; should only affect speed, not behaviour 44 dynarray version 2

45 Bad Example #1 Default-constructor wouldn’t be sensible: student with no identity not allowed! 45 class student { public: student(string name, int student_id);... }; void dynarray_of_student::grow_capacity() {... student* new_items = new student[m_capacity];... } dynarray version 2

46 Bad Example #2 Constructor, destructor w/ side-effects... Extra objects can affect program! 46 int num_animals = 0; struct animal { animal() { num_animals++; } // keep track of animals ~ animal() { num_animals--; } // currently in existence... }; dynarray_of_animal animals; animals.push_back(load("duck.cfg")); animals.push_back(load("pig.cfg")); animals.push_back(load("chicken.cfg")); cout << num_animals << endl; ? dynarray version 2

47 Bad Example #3 Default-constructor can allocate resources If capacity doubles, up to 50% of objects are ‘extra’ and waste even more space! 47 struct sound { int size; double* samples; sound() { *this = load_sound("default.mp3"); } ~ sound() { delete[] samples; } }; dynarray version 2

48 Exercise in Visual Studio See snippet #6 48

49 An Unacceptable Situation Current erase doesn’t destruct object 49 void main() { dynarray_of_string copies; copies.push_back("test"); copies.erase(1); } dynarray version 2 copies 1 't''e''s''t'0 main globals 2 sizecapitems 4 sizechars 4 't''e''s''t'0 'e''s''t'0 object doesn’t officially exist!

50 Solution: In-Place Destructor Need to explicitly call destructor on item! 50 void dynarray_of_string::erase(int index) { assert(index >= 0 && index < m_size); for (int i = index; i < m_size-1; ++i) m_items[i] = m_items[i+1]; // copy from next slot m_size--; m_items[m_size]. ~ string(); // manually destruct item } copies 1 't''e''s''t'0 main globals 2 sizecapitems 4 sizechars ???? 't''e''s''t'0 dynarray version 3

51 Also Need In-Place Constructor C++ feature beyond scope of this course – strange syntax, obscure-yet-important feature Example to give a taste char* mem = new char[4*sizeof(string)]; // allocate bytes string* s = (string*)mem; // point at bytes new (&s[0]) string("test"); // call constructor on 1st slot new (&s[1]) string("test"); // call constructor on 2nd slot s main ???? sizechars ???? 't''e''s''t'0 'e''s''t'0 mem 4 4 dynarray version 3

52 dynarray Version 3 Version 3 is proper array-of-objects: – avoids constructing ‘extra’ objects – destructs objects when they are erased dynarray_of_string available from CS1037 web site under “Lectures” You will not be tested on in-place constructors or destructors! 52

53 dynarray Version 4 We will use C++ templates so that one implementation works for any item type! 53 dynarray dynarray_of_int dynarray_of_double dynarray_of_doubleptr dynarray_of_point dynarray_of_string...


Download ppt "Dynamic Array Objects CS 1037 Fundamentals of Computer Science II TexPoint fonts used in EMF. Read the TexPoint manual before you delete this box.: A AA."

Similar presentations


Ads by Google