object oriented programming elhanan borenstein [email protected] lecture #12 copyrights © elhanan...

28
Object Oriented Programming Elhanan Borenstein [email protected] Lecture #12 copyrights © Elhanan Borenstein

Upload: kane-newsome

Post on 16-Dec-2015

219 views

Category:

Documents


2 download

TRANSCRIPT

Object OrientedProgramming

Elhanan Borenstein

[email protected]

Lecture #12

copyrights © Elhanan Borenstein

Agenda STL – A Brief Overview

Exception Handling

Exceptions and Polymorphism

Reference Counting

copyrights © Elhanan Borenstein

STL Brief Overview & Examples

copyrights © Elhanan Borenstein

STL

copyrights © Elhanan Borenstein

The classes, and algorithms we saw in the previous slides are actually a simulation of the way STL classes, containers and algorithms work. … and now for a brief overview of what STL really includes. In general STL includes the following components:

Data Structures – (vector, list, set, …) Generic Algorithms – (for each, find, sort, …) Object Functions Allocators

Introduction

STL

copyrights © Elhanan Borenstein

STL provides the following data structures: vector – dynamic array (supporting resizing) deque – a queue or a stack list – doubly linked list map – Hashtable (key, value pairs) multimap – Hashtable, supports numerous values for each key set – Hashtable, storing keys only. Each key can only be stored once multiset – Hashtable, storing keys only (may be stored several times)

All DS supports: begin(), end(), insert(…), erase(…), clear(...)

Data Structures

STL

copyrights © Elhanan Borenstein

All algorithms appear in the header file <algorithm> Include: for_each (analog to our Apply()), find, find_if, count, replace, copy, sort,

reverse and many more.

Generic Algorithms

Commonly used with STL. Include: pow, sqrt, sin, other math functions, complex numbers functions, logic

functions, comparison functions and many more.

Object Functions

STL - Examples

copyrights © Elhanan Borenstein

Example : STL1.cpp

Example : STL2.cpp (merging a vector and a list)Names: {She Sells Sea Shealls by the Sea Shore }Number of names starts with S = 6

Numbers Vector { 4 7 8 10 14 16 67 123 }Numbers List { 0 1 2 3 4 5 6 7 }Numbers Deque (merged) { 0 1 2 3 4 4 5 6 7 7 8 10 14 16 67 123 }

Exception Handling

Exceptions

As there may be certain actions which can cause run-time problems, we need some sort of mechanism to report and handle these potential errors.

We can use the return-value mechanism. This mechanism have several problems: We may forget to check the return value. There may not be an available value we can use. Example!!! We have to check the return value for each and every function

separately.

The solution: Exceptions!!! The function does not use the return value but rather throws an

exception. The calling code will include a special block to handle exceptions.

Motivation

Exceptions

Exception handling is implemented with 3 keywords: throw … – when an error occurred in a function it will use “throw” to

throw a certain object (of any type). try – the “problematic” function call, will be nested within a “try”

block. Catch (…) – one or more catch blocks should immediately follow the

try block. if the function throws an exception, this block will handle it. Every catch block can handle only one type of exception. If there may be

more than one type of exception, we should implement several catch block.

The most important feature of that mechanism, is that the function in which the error was detected, forces that calling function to handle it.

Example: exm_exc

Usage

Exceptions

Any type of object can be thrown as exception. It is common to throw objects of a certain class family.

If the exception is not caught, it will percolate up, (function after function) until reaching the main (where it will abort). Conclusions: Somewhere, sometime, someone is going to pay!!!

No casting takes place!!! If more than one catch block fits the exception type, the first

will be used (e.g. void* will take all pointers). catch (…) can catch all types:

Can’t use the thrown object (WHY?) Should be last!!!

An exception can be throws again (using “throw” command)

Exception Handling

Exceptions

The exception handling mechanism was only recently added to C++ as a standard component.

Old libraries and classes may not use this mechanism. Memory Allocation – compiler dependent. Some throw an

exception of type xalloc. Most simply return NULL. Dynamic Cast – compiler dependent. Some throw an exception of

type bad_cast. File Handling – Unfortunately, C++ file handling classes does not

use exceptions. MFC – A good example for exception usage. See documentation.

Haw can we solve that problem?

Compatibility

Exceptions

A function can declare which exception it may throw Should appear in both prototype and implementation).

This mechanism limits the exceptions that the function can throw and thus ensures that if we handle the declared exceptions, we are all covered. void f1() throw (ABC, int);

can throw only objects of type ABC or int !!! void f2() throw (int);

can throw only objects of type int !!! void f3() throw ();

cannot throw any type of object !!! void f4()

can throw any type of object !!!

Declaring thrown Exceptions

Important:A function that throw an exception that was not declare will not be detected in compilation or linkage, but would rather crush the application when this exception is thrown.

Exceptions

Naturally, exceptions are very suitable for constructors (no return value!!!)

If the C’tor did not terminate properly (an exception was thrown), the d’tor will not be activated. Allocated memory should be released before throwing the exception or in the catch block.

but … if the exception was thrown from the C’tor of the derived class, the D’tor of the base class will be activated. (WHY?)

Example: exc_ctor.cpp A few notes!!!

Throwing Exceptions in C’tors and D’tors

Exceptions & Polymorphism

Exceptions and Polymorphism

As we recall, the catch block does not perform casting !!! But still…one exception may fit more than one catch block

when pointers/references are involved (e.g. void* fit int*) We can use this property, combined with polymorphism:

We will implement a catch block for the base class (by ref!!!) This block will also catch all the derived classes Using virtual functions, we can implement a general error

handling code that will work according to he actual error !!!(This mechanism is commonly used in MFC. A full hierarchy of Exception class was implemented)

Introduction

Exceptions and Polymorphism

Note: To use polymorphism, the catch block should receive either a pointer or a reference to the object. using references is sufficient to support polymorphism and doesn’t

require dynamic allocation.

Example: exc_ploy.cpp A few Notes:

CError is the base class of all the exception class. Thus, the catch block will catch also the derived class.

Since DoManyThings() declares it throws CError, it may throw CError or any of it derived classes.

The temporary exception objects lives until the end of the catch block where it was caught.

Example

Reference Counting

Reference Counting

When ever we had a class that used dynamic allocation (e.g. String) we ran into the following two problems:

The Problem:

The Solution:

A brief history of the dual referencing

Who will free the allocated memory (when the object dies)?

How to avoid dual referencing (when copying or assigning to another object)?

If one object changes the content of the allocated memory it will affect all others object with the same reference

If one object dies and free the allocated memory, it will leave all other with a dead reference.

Implement a destructor which will free the allocated memory

Implement a C.C. and assignment oper’ which will create their own copy

+

+

Reference Counting

But…there may be a different (and more efficient) solution. Let’s allow two object to point to the same allocated memory

(as a result of assignment of copy c’tor). To solve the problem of updating the memory:

An object that is about to change the content of the shared memory, will first create its own copy (“Copy on Write”).

To solve the problem of freeing an allocated memory: Only if the object that is being destructed detects that no other object

is pointing to the same memory, it will free that memory.

Advantages - Efficiency: Perform a copy operation only when needed. Use less memory.

A different solution…

Reference Counting

Copy on Write – Simple. When ever we want to change the content of the allocated memory, we will first allocate a new copy.

Freeing Memory – We must implement a Reference Counting mechanism. We will count the number of object pointing to the same memory. Every time an object dies (or create its own copy) we deduce 1

from the counter. If the counter reaches 0 – we will delete that memory.

And technically – we will add to the class String, a pointer to int, which will point to a shared reference counter.

So, how can we implement that concept?

Reference Counting

str1 str2 str3 str4 str5 str6

“John” “Sam” “John”3 2 1

Reference Counting

str1 str2 str3 str4 str5 str6

“John” “John” “John”2 2 1“Bill” 1

Copying

Reference Counting

str1 str2 str3 str4 str5 str6

“John” “John” “John”2 1 1“Bill” 1

Deleting

Reference Counting

str1 str2 str3 str4 str5 str6

“John” “John” “John”2 0 1“Bill” 1

Deleting

Reference Counting

str1 str2 str3 str4 str5 str6

“John” “John” “John”2 0 1“Bill” 1

Deleting

Reference Counting

Example: String.cpp

And, a short example!!!

Questions?

copyrights © Elhanan Borenstein