beginslide oop-1 simple containers in c++ ulist: simple container class uiterators umemory...

21
bEgInSlIdE OOP-1 Simple Containers in C++ Simple Containers in C++ List: simple container class Iterators Memory Allocation Responsibility Mixed type collections Abstract Container Classes Non-Intrusive lists

Upload: henry-chambers

Post on 18-Jan-2016

219 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: BEgInSlIdE OOP-1 Simple Containers in C++ uList: simple container class uIterators uMemory Allocation Responsibility uMixed type collections uAbstract

bEgInSlIdE

OOP-1

Simple Containers in C++ Simple Containers in C++

List: simple container class Iterators Memory Allocation Responsibility Mixed type collections Abstract Container Classes Non-Intrusive lists

Page 2: BEgInSlIdE OOP-1 Simple Containers in C++ uList: simple container class uIterators uMemory Allocation Responsibility uMixed type collections uAbstract

bEgInSlIdE

OOP-2

IteratorsIterators

ii

const N = 100;double a[N];

for (int i = 0; i < N; i++) {... // Process a[i]...

}

const N = 100;double a[N];

for (int i = 0; i < N; i++) {... // Process a[i]...

}

An iterator is used for iterating (traversing/scanning) over all members of a container. Required operations are:

Declare Initialize Get element Increment (Decrement?) Check if last

Array iterators are just integers...

0 1 i i-1 N-1

Page 3: BEgInSlIdE OOP-1 Simple Containers in C++ uList: simple container class uIterators uMemory Allocation Responsibility uMixed type collections uAbstract

bEgInSlIdE

OOP-3

List Container ClassList Container Class

void driver(void){

List mid_east;

mid_east.insert(new Leader("Assad", "Syria"));mid_east.insert(new Leader("Peres", "Israel"));mid_east.insert(new Leader("Hussein", "Jordan"));

List::Iterator i(mid_east);for (; i; ((Leader *)i.next())->print())

;

mid_east.insert(new Leader("Mubarak", "Egypt"));for (i.reset(); i; ((Leader *)i.next())->print())

;}

void driver(void){

List mid_east;

mid_east.insert(new Leader("Assad", "Syria"));mid_east.insert(new Leader("Peres", "Israel"));mid_east.insert(new Leader("Hussein", "Jordan"));

List::Iterator i(mid_east);for (; i; ((Leader *)i.next())->print())

;

mid_east.insert(new Leader("Mubarak", "Egypt"));for (i.reset(); i; ((Leader *)i.next())->print())

;}

Generalization: array with integer iterators - into a generalized list container with typical list operations, which could be used to store objects of any type.

We would like our container class used as follows:

Page 4: BEgInSlIdE OOP-1 Simple Containers in C++ uList: simple container class uIterators uMemory Allocation Responsibility uMixed type collections uAbstract

bEgInSlIdE

OOP-4

Memory Allocation ResponsibilitiesMemory Allocation Responsibilities What’s stored in the container?What’s stored in the container?

objectsContainer must make a copy of all stored objects and be

responsible for allocating and deallocating them. pointers

Who allocates memory for the stored objects? • User - Automatic objects cannot be stored.

• Container - Stored objects are created using copy constructor.

Who deallocates the objects?• User - The user code must keep record of all objects stored

in the container, so that it could erase them.

• Container - Usually the preferred way.

Node::Node(const String& s) : str(s){}Node::Node(const String& s) : str(s){}

Node::Node(const String* s) : sptr(s){}Node::Node(const String* s) : sptr(s){}

Node::Node(const String& s) : sptr(new String(s)){}Node::Node(const String& s) : sptr(new String(s)){}

Page 5: BEgInSlIdE OOP-1 Simple Containers in C++ uList: simple container class uIterators uMemory Allocation Responsibility uMixed type collections uAbstract

bEgInSlIdE

OOP-5

Memory Allocation and Deallocation Memory Allocation and Deallocation Responsibilities with Our InterfaceResponsibilities with Our Interface

void driver(void){

List mid_east;

mid_east.insert(new Leader("Assad", "Syria"));mid_east.insert(new Leader("Peres", "Israel"));mid_east.insert(new Leader("Hussein", "Jordan"));

List::Iterator i(mid_east);for (; i; ((Leader *)i.next())->print())

;

mid_east.insert(new Leader("Mubarak", "Egypt"));for (i.reset(); i; ((Leader *)i.next())->print())

;}

void driver(void){

List mid_east;

mid_east.insert(new Leader("Assad", "Syria"));mid_east.insert(new Leader("Peres", "Israel"));mid_east.insert(new Leader("Hussein", "Jordan"));

List::Iterator i(mid_east);for (; i; ((Leader *)i.next())->print())

;

mid_east.insert(new Leader("Mubarak", "Egypt"));for (i.reset(); i; ((Leader *)i.next())->print())

;}

Allocation in user codeThe container stores pointers to objects allocated in user code.

Allocation in user codeThe container stores pointers to objects allocated in user code.

Deallocation in container codeThe List destructor mid_east.~List executed when driver() returns must delete all the inserted items

Deallocation in container codeThe List destructor mid_east.~List executed when driver() returns must delete all the inserted items

Page 6: BEgInSlIdE OOP-1 Simple Containers in C++ uList: simple container class uIterators uMemory Allocation Responsibility uMixed type collections uAbstract

bEgInSlIdE

OOP-6

The List InterfaceThe List Interface

class List { public: class Node {

...};

class Iterator {

...};

void insert(Node *object) {object->next = first.next;first.next = object;

} .... private:

Node first; // Dummy record};

class List { public: class Node {

...};

class Iterator {

...};

void insert(Node *object) {object->next = first.next;first.next = object;

} .... private:

Node first; // Dummy record};

Nested type definition are used mainly for scope definition and for minimizing the pollution of the global name space.

Nested type definition are used mainly for scope definition and for minimizing the pollution of the global name space.

Indeed, the Ansi-C++ committee decided to add a namespace keyword to C++.

Indeed, the Ansi-C++ committee decided to add a namespace keyword to C++.

Page 7: BEgInSlIdE OOP-1 Simple Containers in C++ uList: simple container class uIterators uMemory Allocation Responsibility uMixed type collections uAbstract

bEgInSlIdE

OOP-7

Declare and initialize - List::iterator i(mid_east)

Initialize - i.reset() Get element - Value of i.next() Increment - i.next() Check if last - Cast to int. If 0 then list exhausted.

List IteratorsList Iterators

...

List::Iterator i(mid_east);for (; i; ((Leader *)i.next())->print())

;...

for (i.reset(); i; ((Leader *)i.next())->print());

...

List::Iterator i(mid_east);for (; i; ((Leader *)i.next())->print())

;...

for (i.reset(); i; ((Leader *)i.next())->print());

Is next a mutator or an observer?

Page 8: BEgInSlIdE OOP-1 Simple Containers in C++ uList: simple container class uIterators uMemory Allocation Responsibility uMixed type collections uAbstract

bEgInSlIdE

OOP-8

Inheritance and Heterogeneous Inheritance and Heterogeneous ContainersContainers

class List {...class Node {

Node *next;Node(Node *n): next(n) {}friend class List;

protected:Node(void): next(NULL) {}virtual ~Node(void) { delete next; }

};...

};

class List {...class Node {

Node *next;Node(Node *n): next(n) {}friend class List;

protected:Node(void): next(NULL) {}virtual ~Node(void) { delete next; }

};...

};Recursive deletion is not terribly efficient...

Recursive deletion is not terribly efficient...

Note that delete NULL is perfectly legal in C++!

Note that delete NULL is perfectly legal in C++!

The List::Node data type is nothing but its identity and linkage information.

The List data type may contain any type derived from List::Node.

Page 9: BEgInSlIdE OOP-1 Simple Containers in C++ uList: simple container class uIterators uMemory Allocation Responsibility uMixed type collections uAbstract

bEgInSlIdE

OOP-9

Inheriting From List::NodeInheriting From List::Node

#include <iostream.h>

class Leader: public List::Node {String name;

String country;public:

Leader(const char *n, const char *c): name(n), country(c) {}void print(void) {

cout << name << ';' << country << '\n';}

};

#include <iostream.h>

class Leader: public List::Node {String name;

String country;public:

Leader(const char *n, const char *c): name(n), country(c) {}void print(void) {

cout << name << ';' << country << '\n';}

};

Leader’s constructor will invoke List::Node’s default constructor

Leader’s destructor will invoke List::Node’s destructor

Page 10: BEgInSlIdE OOP-1 Simple Containers in C++ uList: simple container class uIterators uMemory Allocation Responsibility uMixed type collections uAbstract

bEgInSlIdE

OOP-10

The Type Hierarchy so FarThe Type Hierarchy so Far

ListList List::NodeList::Node List::IteratorList::Iterator

LeaderLeader

The nested class definitions are done only for minimizing pollution of the global name space

Page 11: BEgInSlIdE OOP-1 Simple Containers in C++ uList: simple container class uIterators uMemory Allocation Responsibility uMixed type collections uAbstract

bEgInSlIdE

OOP-11

New & DeleteNew & Delete

class List {...

class Node {...

protected: virtual ~Node(void) { ... }public:

void *operator new(size_t size) {return ::operator new(size);

void operator delete(void *p, size_t size) {::operator delete(p);};...

};

class List {...

class Node {...

protected: virtual ~Node(void) { ... }public:

void *operator new(size_t size) {return ::operator new(size);

void operator delete(void *p, size_t size) {::operator delete(p);};...

};

Employee::new for all classes derived from Employee

Employee::new for all classes derived from Employee

Always static, even if not declared as such!Always static, even if not declared as such!

The size parameter is that of the actual object allocated/deallocated.

The size parameter is that of the actual object allocated/deallocated.

Page 12: BEgInSlIdE OOP-1 Simple Containers in C++ uList: simple container class uIterators uMemory Allocation Responsibility uMixed type collections uAbstract

bEgInSlIdE

OOP-12

Protected Data MembersProtected Data Members

Derived classes cannot access private parts (Or else it would have been a breach of privacy)

Protected data and methods can be accessed only by:

derived classes members friends

Page 13: BEgInSlIdE OOP-1 Simple Containers in C++ uList: simple container class uIterators uMemory Allocation Responsibility uMixed type collections uAbstract

bEgInSlIdE

OOP-13

Protected ConstructorsProtected Constructors

class List {public:

class Iterator;class Node {

friend class List;friend class Iterator;Node *next;Node(Node *n): next(n) {}

protected:Node(void): next(0) {}virtual ~Node(void) { delete next; }

};...

};

class List {public:

class Iterator;class Node {

friend class List;friend class Iterator;Node *next;Node(Node *n): next(n) {}

protected:Node(void): next(0) {}virtual ~Node(void) { delete next; }

};...

};

The next field and the non-default constructor can be used by List and List::Iterator only.

Leader can only use the default constructor of List::Node.

Page 14: BEgInSlIdE OOP-1 Simple Containers in C++ uList: simple container class uIterators uMemory Allocation Responsibility uMixed type collections uAbstract

bEgInSlIdE

OOP-14

List Destruction and Virtual List Destruction and Virtual DestructorsDestructors

ListList

class List {...class Node {

...protected:

virtual ~Node(void) { delete next; }};Node first;

};

class List {...class Node {

...protected:

virtual ~Node(void) { delete next; }};Node first;

};

Destruction sequence List goes out of scope List destructed ט First node destructed ט Other nodes destructed recursively ט

~List::Node must be virtual to guarantee that ~Leader is called when the list is destructed

LeaderLeader

Node

LeaderLeader

Node

LeaderLeader

Node

Page 15: BEgInSlIdE OOP-1 Simple Containers in C++ uList: simple container class uIterators uMemory Allocation Responsibility uMixed type collections uAbstract

bEgInSlIdE

OOP-15

Iterator ImplementationIterator Implementation

class List {...class

public:class Iterator {

Node *first, *curr;public:

Iterator(List& l) { first = &l.first; reset(); }void reset(void) { curr = first->next; }operator int(void) { return curr != NULL; }Node *next(void) {

Node* tmp = curr;if (curr != NULL) curr = curr->next;return tmp;

}};...Node first; // Dummy node used as first list element

};

class List {...class

public:class Iterator {

Node *first, *curr;public:

Iterator(List& l) { first = &l.first; reset(); }void reset(void) { curr = first->next; }operator int(void) { return curr != NULL; }Node *next(void) {

Node* tmp = curr;if (curr != NULL) curr = curr->next;return tmp;

}};...Node first; // Dummy node used as first list element

};

Page 16: BEgInSlIdE OOP-1 Simple Containers in C++ uList: simple container class uIterators uMemory Allocation Responsibility uMixed type collections uAbstract

bEgInSlIdE

OOP-16

Summary: List InterfaceSummary: List Interfaceclass List {

public:class Node {

...};class Iterator {

...};

void insert(Node *object) { object->next = first.next; first.next = object;

}};

class List {public:class Node {

...};class Iterator {

...};

void insert(Node *object) { object->next = first.next; first.next = object;

}};

List stores any class derived from List::Node. Exported operations are insert and iteration Only. Constructor and destructor are generated

automatically.

Page 17: BEgInSlIdE OOP-1 Simple Containers in C++ uList: simple container class uIterators uMemory Allocation Responsibility uMixed type collections uAbstract

bEgInSlIdE

OOP-17

QuizQuizvoid driver(void){

List mid_east;

mid_east.insert(new Leader("Assad","Syria"));mid_east.insert(new Leader("Peres","Israel"));mid_east.insert(new Leader("Hussein","Jordan"));

List::Iterator i(mid_east);for (; i; ((Leader *)i.next())->print())

;

mid_east.insert(new Leader("Mubarak","Egypt"));

for (i.reset(); i; ((Leader *)i.next())->print());

}

void driver(void){

List mid_east;

mid_east.insert(new Leader("Assad","Syria"));mid_east.insert(new Leader("Peres","Israel"));mid_east.insert(new Leader("Hussein","Jordan"));

List::Iterator i(mid_east);for (; i; ((Leader *)i.next())->print())

;

mid_east.insert(new Leader("Mubarak","Egypt"));

for (i.reset(); i; ((Leader *)i.next())->print());

} What will be printed? Describe the allocation and deallocation activities. How is the following an indication of a design problem?

((Leader *)i.next())->print()

Page 18: BEgInSlIdE OOP-1 Simple Containers in C++ uList: simple container class uIterators uMemory Allocation Responsibility uMixed type collections uAbstract

bEgInSlIdE

OOP-18

class List {...

class Iterator {Node *first, *curr;

Node *next(void) {Node* tmp = curr;if (curr != NULL) curr = curr->next;return tmp;

}public:

Iterator(List& l) { first = curr = l.first.next; }void reset(void) { curr = first; }operator int(void) { return curr != NULL; }Node * operator()(void){ return curr; }Iterator& operator++(void){ next(); return *this; }

};...

};...for (List::Iterator i(mid_east); i; ++i)

cout << *(Leader *)i();

class List {...

class Iterator {Node *first, *curr;

Node *next(void) {Node* tmp = curr;if (curr != NULL) curr = curr->next;return tmp;

}public:

Iterator(List& l) { first = curr = l.first.next; }void reset(void) { curr = first; }operator int(void) { return curr != NULL; }Node * operator()(void){ return curr; }Iterator& operator++(void){ next(); return *this; }

};...

};...for (List::Iterator i(mid_east); i; ++i)

cout << *(Leader *)i();

Operator Overloading & Iterators Operator Overloading & Iterators

Why prefix operator++?Why prefix operator++?Assumption: operator<< is overloaded for class Leader

Assumption: operator<< is overloaded for class Leader

Page 19: BEgInSlIdE OOP-1 Simple Containers in C++ uList: simple container class uIterators uMemory Allocation Responsibility uMixed type collections uAbstract

bEgInSlIdE

OOP-19

Iteration FunctionsIteration Functions

void ForEach( List& list, void (*func)(List::Node *current))

{for (List::Iterator i(l); i; ++i) func(i());

}

List::Node *FirstThat(List& list, int (*func)(List::Node *current))

{List::Node *current;

for (List::Iterator i(l); i; ++i)if (func(current = i()))

return current;

return (List::Node *)0;}

void ForEach( List& list, void (*func)(List::Node *current))

{for (List::Iterator i(l); i; ++i) func(i());

}

List::Node *FirstThat(List& list, int (*func)(List::Node *current))

{List::Node *current;

for (List::Iterator i(l); i; ++i)if (func(current = i()))

return current;

return (List::Node *)0;}

Can be used for implementing general purpose iteration and search

Page 20: BEgInSlIdE OOP-1 Simple Containers in C++ uList: simple container class uIterators uMemory Allocation Responsibility uMixed type collections uAbstract

bEgInSlIdE

OOP-20

Using Iteration FunctionsUsing Iteration Functions

void Print(List::Node *n) {

cout << (Leader *)n; }...ForEach(mid_east,Print);...Leader Who, *found;...int Search(List::Node *n) {

return (Leader *)n == Who; }...if ((found = FirstThat(mid_east,Search)) != NULL)

...

void Print(List::Node *n) {

cout << (Leader *)n; }...ForEach(mid_east,Print);...Leader Who, *found;...int Search(List::Node *n) {

return (Leader *)n == Who; }...if ((found = FirstThat(mid_east,Search)) != NULL)

...

Page 21: BEgInSlIdE OOP-1 Simple Containers in C++ uList: simple container class uIterators uMemory Allocation Responsibility uMixed type collections uAbstract

bEgInSlIdE

OOP-21

Memory Allocation Responsibilities:Memory Allocation Responsibilities:Summary and Typical ErrorsSummary and Typical Errors

Better to store pointers in a container Better let the container own the elements:

Elements destroyed when container destroyed.

Typical errors are: Store an automatic object Store a global/static object Store the same object in more than one container. Destroying explicitly an element in the container.