Presentation is loading. Please wait.

Presentation is loading. Please wait.

Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis.

Similar presentations


Presentation on theme: "Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis."— Presentation transcript:

1 Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis

2 Computer Architecture int main() { int i = 0; Card c1; …. return 0; }

3 Memory Model Code Stack Heap int main() { int i = 0; Card c1; …. return 0; } Global

4 int func() { int i = 1; int j = 2; const char* str=“test”; Card a(“3C”); Card b=a; …. return 0; } Card::Card(const char* s) { …. } Program Execution Model Code SectionStack Section i j 2 a.rank a.suit 3 str 1 CLUBS 0 Card::Card() : rank(NO_RANK), suit(NO_SUIT) { } b.rank NO_RANK NO_SUIT 3 CLUBS b.suit Card b; b=a; Card& Card::operator= (const Card& other) { rank= other.rank; suit = other.suit; } Card::~Card() { } 0x12345678

5 Program Execution Model with Heap Allocation Game* makeGame(const char* name) { Game* result = 0; if (strcmp(name,”bridge”)==0) result= new BridgeGame; else if (strcmp(name,”hearts”)==0) result= new HeartsGame; return result; } CodeStackHeap 0x4518ab31 hearts name 0result 0x34567890 0x4518ab31 int strcmp(const char* s1, const char* s2){ …. return result; } 10 1.Find an empty space in heap for HeartsGame. (Time consuming) 2.Execute the constructor of HeartsGame 3.Return the address of the newly created object 0x40123456

6 Differentiate Stack and Heap Objects Card a_card; //  stack object Destructor will be implicitly called when a_card is out of scope. Card* card_ptr = new Card; //  heap object Requires explicit delete Don’t do these delete &a_card; a_card = *(new Card);

7 When to use “new”? Objects have to live beyond current scope Is object copying a viable solution? Good for copy : Card objects  Object size is small  Non-polymorphic Bad for copy : Player, Game objects.  Involve heap memory allocation  Polymorphic Is object swapping a good alternative? Good for objects with embedded heap objects such as  Player,  std::string  All STL containers, like  std::vector, std::set, std::map, …, etc. Not useful for polymorphic classes Game* makeGame(const char* name) { Game* result = 0; if (strcmp(name,”bridge”)==0) result= new BridgeGame; else if (strcmp(name,”hearts”)==0) result= new HeartsGame; return result; }

8 Problem with the interaction between “new” and exception Player* Game::add_player(const char* name) { Player* p = std::find_if(players,player+size, lessThan(name)); if (p != player+size && p->name() ==name) return p; Player* temp = new Player[size+1]; Player* dest = std::copy(players, p, temp); *dest = Player(name); std::copy(p, player+size, dest+1); std::swap(temp, players); delete[] temp; return dest; } players+size name=“Ken” p players Ted Sue Joe Bob p temp Ted Sue dest Ken Joe Bob Could throw exceptions temp won’t be deleted if any exception is thrown

9 How to fix it? Use “try” and “catch”, delete temp in catch clause if any exception is thrown. If non-thrown swap() is defined for Player class, you can use swap() instead of assignment. Only deal with std::bad_alloc exception Not a solution for other possible exceptions Resource Acquisition is Initialization (RAII)

10 Resource Acquisition is Initialization (RAII)‏ Referred as “Guard Idiom” by Dr. Gill. However, the term RAII is more widely used in C++ community. Relies on Stack object would be destructed upon out of scope. Use stack object to hold the ownership of a heap object, or any other resource that requires explicit clean up. Heap object ( or resources) is release upon the destruction of the RAII stack object.

11 RAII Utility Classes template class scoped_ptr { T* ptr; public : scoped_ptr(T* p=0) :ptr(p) {} ~scoped_ptr() { delete ptr; } void reset(T* p) { delete ptr; ptr = p; } T* get() { return ptr;} void swap(scoped_ptr& ); } template class vector { T* ptr; size_t sz; public : vector() :ptr(0), sz(0) {} ~ vector () { delete ptr[]; } … void swap(vector& ); }

12 How to use RAII Game* game; if (strcmp (argv[1], “bridges”)==0) game = new BridgeGame ; else if (strcmp(argv[1],”hearts”)==0) game = new HeartsGame ; game->add_player(“tom”); game->add_player(“ted”); game->refresh(); game->deal_hands(); game->score_hands(); game->print(); delete game; boost::scoped_ptr game; if (strcmp (argv[1], “bridges”)==0) game.reset(new BridgeGame); else if (strcmp(argv[1],”hearts”)==0) game.reset(new HeartsGame); game->add_player(“tom”); game->add_player(“ted”); game->refresh(); game->deal_hands(); game->score_hands(); game->print();

13 Stock Smart Pointers Boost (www.boost.org) scoped_ptr shared_ptr weak_ptr std auto_ptr

14 boost::scoped_ptr Used for a single object, not for array Noncopyable scoped_ptr game1(new BridgeGame); // OK scope_ptr game2(game1); // Won’t compile scoped_ptr game3; // OK game3 = game1; // Won’t compile game3.reset(new BridgeGame); // OK game3.swap(game1); // OK Useful to implement pointer to implementation (pimple) idiom.

15 C++ Pimple idiom (Conceptual View)

16 C++ Pimple idiom (implementation View) /// Foo.h #include struct FooImpl; // forward declaration class Foo { using namespace boost; scoped_ptr pimpl; public: Foo(); void method1(); }; /// Foo.cc #include “Foo.h” struct FooImpl { int state; … }; Foo::Foo() : pimpl(new FooImpl) { } void Foo::method1() { ++ pimpl->state; … }

17 Why use pimple idiom Separation between interface and implementation Allows library vendors keep implementation detail secrete Avoid client recompilation for the change of internal data structure. Exception safety

18 std::auto_ptr Similar to scoped_ptr, but copyable. Copy represents ownership transfer. Best used for function parameters and return types in the case when ownership transfer is needed. auto_ptr makeGame(const char* name) { if (strcmp(name, “bridge”) ==0) return auto_ptr (new BridgeGame); else if (strcmp(name, “hearts”) == 0) return auto_ptr (new HeartsGame); return auto_ptr (); }

19 boost:shared_ptr Reference counting semantics. Simplest form of garbage collection a : share_ptr ptr pcount :Foo 1 : int Class View Object View b : share_ptr ptr pcount shared_ptr a(new Foo); shared_ptr b = a; 2 : int 0 : int

20 Reference Counting and Cyclic Dependency Problem

21 void fun() { shared_ptr cse(new Department); shared_ptr cse332(new Course); cse332.department = cse; cse.courses.push_back(cse332); } cse cse332 : Department: Course 1 : int coursesdepartment 2 : int courses[0] 2 : int

22 Boost::weak_ptr Used together with shared_ptr to avoid cyclic reference counting problem. Does not increase reference count during construction and copying. Class Department { vector > courses; }; Class Course { weak_ptr department; }; void fun() { shared_ptr cse(new Department); shared_ptr cse332(new Course); cse332.department = cse; cse.courses.push_back(cse332); } The reference count is not incremented

23 Collection of Objects Player* players = new Player[size]; Need explicit delete statement for players array vector players; Expensive Player object copying vector players; May require explicit delete statement for each individual Player object vector > and vector > won’t compile. because all containers in C++ standard requires that any element a and b in the container, After a = b then a == b

24 Collection of Objects vector > players Ownership to Player objects are not exclusive Comparing to vector, it incurs small overhead for reference counting. No need for explicit delete statement. boost::ptr_vector players; Only heap objects can be added to the container. It has the exclusively ownership for the objects it contains. No need for explicit delete statement.

25 Preferred Form for Object Collections vector, vector Contained objects are cheap to copy ptr_vector, ptr_vector Contained objects are expensive to copy or polymorphic. vector > or vector > The ownership of the contained object cannot be exclusively held.

26 Summary Dynamic memory allocation are expensive, avoid it if you can. Be careful with implicit object copying. Don’t write code that requires explicit “delete” statement. For single object : use smart pointers For collection of value types : use standard container classes For collection of pointers : use boost ptr containers or shared_ptr.


Download ppt "Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis."

Similar presentations


Ads by Google