Object Oriented Software Design - II

Similar documents
Design Patterns in C++

Exception-Safety Issues and Techniques

Allocation & Efficiency Generic Containers Notes on Assignment 5

Exception Safety. CS 311 Data Structures and Algorithms Lecture Slides Wednesday, October 28, Glenn G. Chappell. continued

Object Oriented Software Design II

A Whirlwind Tour of C++

Advanced Programming in C++ Container Design I

Exception Handling: A False Sense of Security Cargill, P1

Exception Namespaces C Interoperability Templates. More C++ David Chisnall. March 17, 2011

Fundamentals of Programming

Design Patterns in C++

Introduction to the C programming language

Introduction to the C programming language

C++ Coding Standards. 101 Rules, Guidelines, and Best Practices. Herb Sutter Andrei Alexandrescu. Boston. 'Y.'YAddison-Wesley

COMP6771 Advanced C++ Programming

Overview of C++: Part 1

Object-Oriented Principles and Practice / C++

Object Oriented Software Design

class Polynomial { public: Polynomial(const string& N = "no name", const vector<int>& C = vector<int>());... };

Midterm Review. PIC 10B Spring 2018

CS32 - Week 1. Umut Oztok. June 24, Umut Oztok CS32 - Week 1

Exception Safe Coding

CS 251 INTERMEDIATE SOFTWARE DESIGN SPRING C ++ Basics Review part 2 Auto pointer, templates, STL algorithms

C and C++ 7. Exceptions Templates. Alan Mycroft

1/29/2011 AUTO POINTER (AUTO_PTR) INTERMEDIATE SOFTWARE DESIGN SPRING delete ptr might not happen memory leak!

Data Structures (INE2011)

COMP6771 Advanced C++ Programming

CS11 Advanced C++ Fall Lecture 3

Laboratorio di Tecnologie dell'informazione

Object Oriented Software Design II

CMSC 202 Final May 19, Name: UserID: (Circle your section) Section: 101 Tuesday 11: Thursday 11:30

Object Oriented Software Design II

Object-Oriented Principles and Practice / C++

2 ADT Programming User-defined abstract data types

Vector and Free Store (Pointers and Memory Allocation)

A linear structure is an ordered (e.g., sequenced) arrangement of elements.

Templates. Giuseppe Lipari Scuola Superiore Sant Anna Pisa. June 8, 2009

G52CPP C++ Programming Lecture 16

Exceptions. CandC++ 7. Exceptions Templates. Throwing exceptions. Conveying information

(heavily based on last year s notes (Andrew Moore) with thanks to Alastair R. Beresford. 7. Exceptions Templates 2/1. Throwing exceptions 14 }

COMP6771 Advanced C++ Programming

University of Illinois at Urbana-Champaign Department of Computer Science. First Examination

Standard-Library Exception Safety

Exceptions and Design

COMP6771 Advanced C++ Programming

CSC 1600 Memory Layout for Unix Processes"

4.1 Ordered Lists Revisited

Fast Introduction to Object Oriented Programming and C++

Object Oriented Software Design

mywbut.com Exception Handling

CPSC 427: Object-Oriented Programming

Object Oriented Software Design II

05-01 Discussion Notes

Chapter 1: Object-Oriented Programming Using C++

Object-Oriented Programming for Scientific Computing

Short Notes of CS201

void fun() C::C() // ctor try try try : member( ) catch (const E& e) { catch (const E& e) { catch (const E& e) {

A linear structure is an ordered (e.g., sequenced) arrangement of elements.

CS201 - Introduction to Programming Glossary By

The issues. Programming in C++ Common storage modes. Static storage in C++ Session 8 Memory Management

University of Illinois at Urbana-Champaign Department of Computer Science. First Examination

C++ TEMPLATES. Templates are the foundation of generic programming, which involves writing code in a way that is independent of any particular type.

AIMS Embedded Systems Programming MT 2017

CSE 374 Programming Concepts & Tools. Hal Perkins Spring 2010

Creating a String Data Type in C

Variant: a type-safe union without undefined behavior (v2).

4/27/2014. Templates II. Warmup Write the templated Swap function. Class Templates CMSC 202

Object-Oriented Programming for Scientific Computing

Networked Embedded System Patterns for C Developers. Overview of C (& C++) Programming Styles. Douglas C. Schmidt

Assertion. C++ Object Oriented Programming Pei-yih Ting NTOU CS

Fundamentals of Programming

Quiz Start Time: 09:34 PM Time Left 82 sec(s)

Static initializers in C++

CS201 Latest Solved MCQs

Chapter 17 vector and Free Store

C++ Exception Handling 1

Exercise 6.2 A generic container class

Chapter 17 vector and Free Store. Bjarne Stroustrup

Object Oriented Software Design - I

Overview. Constructors and destructors Virtual functions Single inheritance Multiple inheritance RTTI Templates Exceptions Operator Overloading

Homework 4. Any questions?

Special Member Functions. Compiler-Generated Destructor. Compiler-Generated Default Constructor. Special Member Functions

double d0, d1, d2, d3; double * dp = new double[4]; double da[4];

Part X. Advanced C ++

Object Oriented Software Design II

Introduction to C++ Giuseppe Lipari April 27, Scuola Superiore Sant Anna Pisa

Object Oriented Software Design II

Everything You Ever Wanted To Know About Move Semantics

Objects Managing a Resource

3.Constructors and Destructors. Develop cpp program to implement constructor and destructor.

Software Design and Analysis for Engineers

Announcements. Lecture 05a Header Classes. Midterm Format. Midterm Questions. More Midterm Stuff 9/19/17. Memory Management Strategy #0 (Review)

Chapter 16: Exceptions, Templates, and the Standard Template Library (STL)

Value Semantics and Concept Based Polymorphism Sean Parent Principal Scientist Adobe Systems Incorporated. All Rights Reserved.

IS 0020 Program Design and Software Tools

CSCI-1200 Data Structures Fall 2011 Lecture 24 Garbage Collection & Smart Pointers

A Generic Non-intrusive Smart Pointer Implementation

What will happen if we try to compile, link and run this program? Do you have any comments to the code?

Intermediate Programming, Spring 2017*

Hazard Pointers. Safe Resource Reclamation for Optimistic Concurrency

Transcription:

Object Oriented Software Design - II Safety to exceptions Giuseppe Lipari http://retis.sssup.it/~lipari Scuola Superiore Sant Anna Pisa April 12, 2012 G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 1 / 41

Outline 1 Exception safety 2 A safe stack Constructor and destructor Copying and assigning Push and pop 3 An alternative implementation Placement operator new Implementing Stack G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 2 / 41

Exception safety Informally, exception safety means that a piece of software is well-behaved with respect to exceptions The program must remain in a consistent state when an exception is raised (no memory leaks, no half modified structures, etc.) Exception safety is always important, but it is particularly important when writing libraries, because the customer expects a well behaved library to not lose resources or remain inconsistent when an exception is raised the user expects to catch the exception and continue with the program, so the data structures must remain consistent Exception safety is particularly difficult when dealing with templates, because we do not know the types, so we do not know what can raise an exception G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 3 / 41

An example of unsafe code // In some header file: void f( T1*, T2* ); // In some implementation file: f( new T1, new T2 ); This can lead to a memory leak. Suppose that the evaluation order is the following: 1 Memory is allocated for T1, then T1 is constructed 2 Memory is allocated for T2, then T2 is constructed 3 function f() is called If the constructor of T2 throws an exception for whatever reason, the memory for T1 is not deallocated, and T1 is not destroyed Rule: don t use two new operations in the same expression, because some of them can leak in case of exception notice that we do not know the exact order of execution of steps 1 and 2. see example exc_function G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 4 / 41

Definition There are three properties that have to do with exception safety (Abrahams Guarantees) Basic Guarantee: If an exception is thrown, no resources are leaked, and objects remain in a destructible and usable but not necessarily predictable state. This is the weakest usable level of exception safety, and is appropriate where client code can cope with failed operations that have already made changes to objects state. Strong Guarantee: If an exception is thrown, program state remains unchanged. This level always implies global commit-or-rollback semantics, including that no references or iterators into a container be invalidated if an operation fails. Nothrow Guarantee: The function will not emit an exception under any circumstances. It turns out that it is sometimes impossible to implement the strong or even the basic guarantee unless certain functions are guaranteed not to throw (e.g., destructors, deallocation functions). G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 5 / 41

Outline 1 Exception safety 2 A safe stack Constructor and destructor Copying and assigning Push and pop 3 An alternative implementation Placement operator new Implementing Stack G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 6 / 41

Problem How to write a generic implementation of the Stack container that is safe to exceptions? We will solve the problem step by step (see Exceptional C++, by Herb Sutter) template <class T> class Stack { public: Stack(); ~Stack();... private: T* v_; size_t vsize_; size_t vused_; ; G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 7 / 41

Requirements first requirement: weak guarantee (no memory leak) second requirement: strong guarantee (state is always consistent) third requirement: transparency (all exceptions must be forwarded to the user of Stack) Let s start by writing the constructor and destructor G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 8 / 41

Outline 1 Exception safety 2 A safe stack Constructor and destructor Copying and assigning Push and pop 3 An alternative implementation Placement operator new Implementing Stack G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 9 / 41

Constructor template<class T> Stack<T>::Stack() : v_(0), vsize_(10), vused_(0) { v_ = new T[vsize_]; The implementation is correct because: It is transparent (no exception is caught) no memory leak if an exception is thrown, Stack is not constructed, so everything remains in consistent state G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 10 / 41

Memory leak? v_ = new T[vsize_]; To understand why there are no memory leaks, let s see how the new operator works The new operator 1 first allocates memory for 10 objects of type T 2 then, it invokes the default constructor of T 10 times Both (1) and (2) can throw an exception if (1) throws a bad_alloc (because we run out of memory), no memory is allocated, everything works correctly if any of the default constructors of T throw an exception the previously constructed objects are destructed and the memory is released G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 11 / 41

Memory leak? v_ = new T[vsize_]; To understand why there are no memory leaks, let s see how the new operator works The new operator 1 first allocates memory for 10 objects of type T 2 then, it invokes the default constructor of T 10 times Both (1) and (2) can throw an exception if (1) throws a bad_alloc (because we run out of memory), no memory is allocated, everything works correctly if any of the default constructors of T throw an exception the previously constructed objects are destructed and the memory is released Warning: the destructors must not throw exceptions, otherwise it is impossible to build anything that is safe to exceptions We implicitly require that T:: T() does not throw G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 11 / 41

Destructor template<class T> Stack<T>::~Stack() { delete v_[]; We just said that we require that T:: T() will never throw an exception if this is true, also delete cannot throw, and also our destructor therefore, this function respects the no-throw guarantee G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 12 / 41

Outline 1 Exception safety 2 A safe stack Constructor and destructor Copying and assigning Push and pop 3 An alternative implementation Placement operator new Implementing Stack G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 13 / 41

Copy and assignment We now write the copy constructor and the assignment operator template <class T> class Stack { public: Stack(); ~Stack(); Stack(const Stack &); Stack & operator=(const Stack &);... private: T* v_; size_t vsize_; size_t vused_; ; G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 14 / 41

First try To simplify the implementation, we first implement an helper function that performs the copy, this will be used by the copy constructor and by the assignment operator template<class T> T* Stack<T>::NewCopy(const T* src, size_t srcsize, size_t destsize) { assert(destsize >= srcsize); T *dest = new T[destsize]; try { copy(src, src+destsize, dest); catch (...) { delete dest[]; // cannot raise exceptions throw; // re-throws the same exception return dest; G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 15 / 41

Analysis... T *dest = new T[destsize];... If it throws an exception, the rest of the function is not executed, all memory is correctly deallocated (as in the constructor case) G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 16 / 41

Analysis... T *dest = new T[destsize];... If it throws an exception, the rest of the function is not executed, all memory is correctly deallocated (as in the constructor case) try { copy(src, src+destsize, dest); catch (...) { delete dest[]; // cannot raise exceptions throw; // re-throws the same exception If the copy throws an exception (due to the assignment operator of T) we catch it, delete all memory, and re-throw (for transparency) G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 16 / 41

Assignment template<class T> Stack<T>& Stack<T>::operator=(const Stack<T>&other) { if (this!= other) { T* v_new = NewCopy(other_v, other.vsize_, other.vsize_); delete v_[]; v_ = v_new; vsize_ = other.vsize_; vused _ = other.v_used_; return *this; If NewCopy throws, nothing else is changed all other instructions cannot throw (they operate on std types) G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 17 / 41

Outline 1 Exception safety 2 A safe stack Constructor and destructor Copying and assigning Push and pop 3 An alternative implementation Placement operator new Implementing Stack G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 18 / 41

Push and pop implementation We need extra care here. Suppose initially that we have the following prototype: template <class T> class Stack { public: Stack(); ~Stack(); Stack(const Stack &); Stack & operator=(const Stack &); size_t Count() const { return vused_; void Push(const T &); T Pop(); private: T* v_; size_t vsize_; size_t vused_; ; G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 19 / 41

Push Again, let s first operate on a temporary, then we commit at the end template<class T> void Stack<T>::Push(const T& t) { if (vused_ == vsize_) { size_t vsize_new = vsize_ * 2 + 1; T* v_new = NewCopy(v_, vsize_, vsize_new); delete v_[]; v_ = v_new; vsize_ = vsize_new; v_[vused_] = t; ++vused_; G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 20 / 41

Pop is a problem template<class T> T Stack<T>::Pop() { if (vused_ == 0) { throw "Pop from an empty stack"; else { T result = v_[vused_ - 1]; -- vused_; return result; This function looks correct, but unfortunately has an hidden problem G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 21 / 41

Pop is a problem template<class T> T Stack<T>::Pop() { if (vused_ == 0) { throw "Pop from an empty stack"; else { T result = v_[vused_ - 1]; -- vused_; return result; This function looks correct, but unfortunately has an hidden problem Stack<string> s;... string s2; s2 = s.pop(); If the last copy fails, we extracted an element, but this will never reach destination we lost an element! G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 21 / 41

Two solutions We can change the Pop() function in two ways: first solution template<class T> void Stack<T>::Pop(T &result) { if (vused_ == 0) { throw "Pop from an empty stack"; else { result = v_[vused_ - 1]; -- vused_; G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 22 / 41

STL solution Second solution is to add a Top() function, and let Pop() only remove the element, without returning it template<class T> void Stack<T>::Pop() { if (vused_ == 0) throw "..."; else -- vused_; template<class T> T Stack<T>::Top() { if (vused_ == 0) throw "..."; else return v_[vused_ - 1]; This is the way chosen by the STL implementation of stack and other containers G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 23 / 41

What we require Let s see what we require to class T for the Stack to work properly 1 A default constructor 2 a copy constructor 3 an assignment operator 4 a destructor that does not throw we can do better than this, namely remove requirements 1 and 3 G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 24 / 41

Outline 1 Exception safety 2 A safe stack Constructor and destructor Copying and assigning Push and pop 3 An alternative implementation Placement operator new Implementing Stack G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 25 / 41

Remove the try/catch block We can remove the try/catch block in the NewCopy by using a different technique This technique is quite general and it is based on the pimpl pattern, plus a two-phase structure (do the work, then commit at the end) it can be reused in you code quite easily Let s start by moving all implementation in a separate class template<class T> class StackImpl { public: StackImpl(size_t size=0); ~StackImpl(); void Swap(StackImpl &other) throw(); T *v_; size_t vsize_; size_t vused_; private: StackImpl(const StackImpl &); StackImpl& operator=(const StackImpl &); ; G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 26 / 41

Outline 1 Exception safety 2 A safe stack Constructor and destructor Copying and assigning Push and pop 3 An alternative implementation Placement operator new Implementing Stack G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 27 / 41

The placement operator new Before continuing we need to analyse again the process of dynamically creating an object a call new T can be divided into two parts: 1 Memory allocation 2 Construction of the object on the specific address Step (1) is performed by the operator new Step (2) is performed by the placement operator new T *p = operator new(sizeof(t)); // step 1 new (p) T(); // step 2 // the two steps above are equivalent to // p = new T; G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 28 / 41

Operator new and placement The operator new is equivalent to the standard function malloc of the C language It is a global function that just allocates a certain amount of bytes The placement operator new, instead, calls the constructor and forces the object to be build on the memory pointed by the first parameter T *p = operator new(sizeof(t)); // step 1 new (p) T(); // step 2 The placement operator new can be used to build an object on your own memory location For example, it is possible to reserve a certain amount of memory in a specific location (for example global memory) and then call the placement operator to create the object exactly on that location It may be useful to implement custom memory allocation G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 29 / 41

Operator delete and destructor Also, delete consists of two parts: 1 calling the destructor 2 releasing the memory It is possible to call the destructor without releasing the memory And it is possible to release the memory without calling the destructor p->~t(); operator delete(p); G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 30 / 41

std::construct() and std::destroy() The STL library provides a nice wrapper for using the placement operator; template<class T1, class T2> void construct(t1* p, const T2& value) { new (p) T1(value); template<class T> void destroy(t* p) { p->~t(); template<class FwdIter> void destroy(fwditer first, FwdIter last) { while (first!= last) { destroy(first); ++first; G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 31 / 41

Constructor template<class T> StackImpl<T>::StackImpl(size_t size): v_(0), vsize_ (size), vused_(0) { if (size > 0) v_ = operator new(sizeof(t)*size); The operator new only allocates memory, but it does not call the constructor of T That s quite different from calling new T[size_] therefore, no object of T is built if operator new throws bad_alloc, the objects are not built and we are safe G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 32 / 41

Destructor template<class T> StackImpl<T>::~StackImpl() { destroy(v_, v_+vused_); operator delete(v_); destroy() calls all destructors for vused_ objects destroy() cannot raise any exception operator delete is the dual of operator new: it just frees the memory (without calling any destructor) G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 33 / 41

The Swap function Now we can continue by looking at a very important function template <class T> void StackImpl<T>::Swap(StackImpl &other) throw() { swap(v_, other.v_); swap(vused_, other.vused_); swap(vsize_, other.vsize_); Here we are only swapping pointers or size_t members, there is no function call, so no exception is possible this function swaps the two internal representations of Stack G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 34 / 41

Outline 1 Exception safety 2 A safe stack Constructor and destructor Copying and assigning Push and pop 3 An alternative implementation Placement operator new Implementing Stack G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 35 / 41

Stack class Now we are ready to implement the Stack class template <class T> class Stack : private StackImpl<T> { public: Stack(size_t size = 0); ~Stack(); Stack(const Stack&); Stack& operator=(const Stack&); size_t Count() const; void Push(const T&); T& Top(); void Pop(); ; G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 36 / 41

Constructor and destructor template<class T> Stack<T>::Stack(size_t size) : StackImpl<T>(size) { template<class T> Stack<T>::~Stack() { The destructor of StackImpl is automatically called, and Stack has nothing to destruct (we could also remove the definition, because the compiler provides a standard one for us) G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 37 / 41

Copy constructor template<class T> Stack<T>::Stack(const Stack<T>& other) : StackImpl<T>(other.vused_) { while(v_used_ < other.vused_) { construct(v_ + vused_, other.v_[vused_]); ++vused_; StackImpl constructor can raise an exception Nothing bad can happen A copy constructor of T can raise an exception In that case, the destructor of StackImpl will destroy exactly all objects that have been created (see StackImpl()) G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 38 / 41

Assignment operator template<class T> Stack<T>& Stack<T>::operator=(const Stack<T>& other) { Stack<T> temp(other); // constructs a temporary copy Swap(temp); // swaps internal implementations return *this; // temp will be destroyed If the copy constructor fails, nothing bad happens the Swap cannot throw It follows that this is safe to exceptions G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 39 / 41

Push template<class T> void Stack<T>::Push(const T& elem) { if (vused_ == vsize_) { Stack<T> temp(vsize_*2+1); while (temp.count() < vused_) temp.push(v_[temp.count()]); temp.push(elem); Swap(temp); else { construct(v_ + vused_, elem); ++vused_; Discuss why this is safe Push and Pop did not change G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 40 / 41

A general technique It turns out that this is a general technique Put all implementation in a inner class Your class will have a pointer to the implementation, or derive privately from the implementation do all the work on a copy when everything is safe, swap the pointers (cannot throw exceptions) Exercise: Write the Stack implementation using the pimpl idiom instead of the private inheritance G. Lipari (Scuola Superiore Sant Anna) Exception Safety April 12, 2012 41 / 41