the beauty of destruction pete isensee microsoft [email protected] game developers conference march...

28
The Beauty of Destruction Pete Isensee Microsoft [email protected] Game Developers Conference March 2009

Upload: benny-mothershed

Post on 11-Dec-2015

216 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

The Beauty of Destruction

Pete [email protected] Developers Conference March 2009

Page 2: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

C++ Destructor Definition• One• Special• Deterministic• Automatic• Symmetric• Member• Function

• With• A special name• No parameters• No return type

• Designed to• Give last rites• Before object

death

Page 3: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

Language ComparisonLanguage

Name Notation

Deterministic

Notes

C n/a n/a n/aC++ Destructor ~T() YesC++/CLI Destructor ~T() YesC++/CLI Finalizer !T() No Called during

GCC# Finalizer ~T() No Called during

GCC# IDisposabl

eDispose()

No

Java Finalizer finalize() No Called during GC

Page 4: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

When Destructors Are InvokedScenario Destructor called NotesNamed automatic Scope exitFree store delete operator Prior to memory being freedStatics and globals Program exit Reverse order of constructionArray elements From last element to firstSTL container elements

Unspecified order

Temporary End of expression in which it was created

If bound to reference or named object, when object exits scope

Exception thrown Stack unwindingExplicit dtor p->~T();exit() For global & static objects Reverse order of constructionabort() No; global & static dtors not

called

Page 5: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

Order of Destruction• Rule of Thumb: Reverse order of

construction• Specifically:

1. Destructor body2. Data members in reverse order of declaration3. Direct non-virtual base classes in reverse

order4. Virtual base classes in reverse order

Page 6: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

Destruction Order Exampleclass Human : Ego, virtual Id {};class Vulcan : Katra, Kolinahr {};class Spock : Human, Vulcan{ Tricorder t; Phaser p; };Spock s;

SpockTricorderPhaserHuman

Ego

Id

VulcanKatra

Kolinahr

61

32

7

4

9

8

5

Page 7: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

Implicit Destructors• Not specified by the programmer• Inline by default• Public• Recommended for struct-like POD-only

objects• For everything else, avoid implicit

destructors • Better debugging• Improved perf analysis

Page 8: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

Trivial Destructors• Destructors that never ever do anything

• Compiler can optimize away

• Requirements• Implicit• Not virtual• All direct base classes have trivial dtors• All non-static members have trivial dtors

Page 9: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

Virtual Destructors• Guarantee that derived classes get cleaned up• Rule of thumb: if class has virtual functions, dtor

should be virtual• If delete on a Base* could ever point to a Derived*

• Perf: Obj with any virtual funcs includes a vtable ptr

• Idiom exceptions: mixin classes• Pure signals abstract class

virtual ~T() = 0 { }

Page 10: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

Partial Construction & Destruction• Dtors are only called for fully constructed

objs• If a ctor throws, obj was not fully

constructed• Object dtor will not be called• But fully constructed subobjects will be

destroyed

• Always use RAII within ctors• Resource Acquisition Is Initialization

Page 11: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

Virtual Functions in Destructors• Virtual functions are not virtual inside

dtorsclass Helmsman {public: // Red alert! virtual ~Helmsman() { Release(); }protected: virtual void Release() {}};class Sulu : public Helmsman { … };

Page 12: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

C++ Exception Handling• Destructors : Exceptions :: Spock : Kirk• Wrap any function that acquires a resource

in a class where dtor releases the resource• Never allow an exception to exit a dtor

• Best: don’t throw in the dtor• OK: wrap throwing code in a try/catch

• Good advice even if you don’t use C++EH

Page 13: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

Multithreading• You are responsible for protecting objects

and their contents• Sharing an object across threads

• Use shared_ptr• Or some other reference counting• Or otherwise ensure only one thread can

destroy

• Protect shared memory (global counters, ref counts) in dtors

Page 14: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

delete and Destructorsdelete p is a two-step process. Pseudo code:

// T* p = new T(…); ≈T *p = (T*)operator new( sizeof(T) );new (p) T(…); // placement new

// delete p ≈if( p != NULL ) { p->~T(); // explicit destructor operator delete( p );}

Page 15: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

Explicit Destructors• Destructors can be called directly• Avoid 99.99% of the time• Very powerful for custom memory

scenarios• Example uses

• w/ placement new• STL allocators

void* p = Alloc(…);Kirk* pk = new (p) Kirk;pk->~Kirk();Free( pk );

Page 16: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

std::allocator• Allocators enable custom STL container

memory• Two key destructive functions

void allocator::destroy( T* p ){ ((T*)p)->~T(); } // default impl.

void allocator::deallocate( T* p, size_type ){ operator delete( p ); } // default impl.

Page 17: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

Case Study: std::vectortemplate <class T> vector::~vector(){ if( m_pFirst != 0 ) { for( T* p = m_pFirst; p != m_pLast; ++p ) m_Alloc.destroy( p ); m_Alloc.deallocate( m_pFirst ); }}

Page 18: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

shared_ptr• Templated non-intrusive deterministically

referenced-counted smart pointer

Object Category Owned By Their Destroyed WhenAutomatic Block Control Leaves BlockData Members Parent Parent diesElements Container Container diesDynamically Allocated shared_ptrs All shared_ptrs die

shared_ptr<T> sp( new T(…) );

Page 19: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

Case Study: tr1::shared_ptrtemplate <class T>shared_ptr::~shared_ptr(){ if( m_pRep != NULL ) // if we’re not a NULL ptr { // and we’re the last owner if( InterlockedDecrement( &m_pRep->RefCount ) == 0 ) { // dispose of the shared object delete m_pSharedPtr; // use deleter if specified // if we’re done with the control block if( InterlockedDecrement( &m_pRep->WeakRefCount ) == 0 ) delete m_pRep; // use allocator.destroy if specified } }}

Page 20: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

shared_ptr deleters• Deleter: a functor called on the stored raw

pointer when ref count hits zero

template <class T> struct Deleter{ void operator()( T* p ) { Free( p ); } };

Khan* p = Alloc(…);shared_ptr<Khan> sp( p, Free );shared_ptr<Khan> sp( p, Deleter<Khan>() );

Page 21: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

Destructor Idioms to Love• delete p• if (p!=NULL) free(p)• CloseHandle()• DeleteCriticalSection()• SetEvent()• pComPtr->Release()• --refCount• InterlockedDecrement(

)• flush()• try { Close() }

catch( … )• closesocket()• assert( … )• { }

Page 22: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

Destructor Gotchas: Red Alert• delete a; delete b• if( p != NULL ) delete p• m_Handle = NULL• Cleanup()• m_Member.Cleanup()• for( itr = v.beg(); itr != v.end(); ++itr ) delete *itr

Page 23: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

Case Study: Multiple owned resourcesstruct Uhura { X* p; Y* q; };// Red alert: leak potentialUhura::Uhura() : p(new X), q(new Y) { }Uhura::~Uhura() { delete p; delete q; }

struct Uhura { shared_ptr<X> sp; shared_ptr<Y> sq; };// SafeUhura::Uhura() : sp(new X), sq(new Y) { }Uhura::~Uhura() {}

Page 24: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

Performance• Destructors are called a LOT• They’re invisible in code• Streamline common dtors• The best dtor is empty• Inlining• Profile

}Lots o’ destruction here

Page 25: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

Enterprise::~Enterprise(){}

Case Study: Destructor TuningEnterprise::~Enterprise(){ Unload(); m_ReactorCore.Empty(); if( m_pOrdnance != NULL ) { delete m_pOrdnance; m_pOrdnance = NULL; } if( m_hAlert != NULL ) { CloseHandle(m_hAlert); m_hAlert = NULL; } for( int i = 0; i < m_CrewSize; i++ ) delete m_Crew[i];}

Enterprise::~Enterprise(){ delete m_pOrdnance; if( m_Alert != NULL ) CloseHandle( m_hAlert ); for( int i = 0; i < m_CrewSize; i++ ) delete m_Crew[i];}

Page 26: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

• Never own more than a single raw resource

• Never let any exceptions escape a dtor• Never call virtual funcs from a dtor• Avoid clearing data unnecessarily (e.g.

zeroing memory, setting ptrs to NULL)• Avoid implicit dtors for non-PODs• Avoid dtors that call other member funcs

Best Practices

Page 27: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

Best Practices: Do This• Embrace RAII: wrap any function that

acquires a resource in a class where the dtor releases

• Embrace shared_ptrs to avoid leaks and deletes

• Virtual dtor iff delete Base* could be a Derived*

• Validate state in dtors: guaranteed choke point

• The best destructor: an empty destructor• Second best: releasing a single resource

Page 28: The Beauty of Destruction Pete Isensee Microsoft pkisensee@msn.com Game Developers Conference March 2009

© 2009 Microsoft Corporation. All rights reserved.This presentation is for informational purposes only. Microsoft makes no warranties, express or implied, in this summary.

http://www.xna.com

© 2009 Microsoft Corporation. All rights reserved.This presentation is for informational purposes only. Microsoft makes no warranties, express or implied, in this summary.

http://www.xna.com