writing correct c++ programs without “delete” huang-ming huang cse332 guest lecture washington...
TRANSCRIPT
![Page 1: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/1.jpg)
Writing Correct C++ Programs without
“delete”
Huang-Ming HuangCSE332 Guest Lecture
Washington University in St. Louis
![Page 2: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/2.jpg)
Computer Architecture
int main() { int i = 0; Card c1; ….
return 0;}
![Page 3: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/3.jpg)
Memory Model
Code
Stack
Heap
int main() { int i = 0; Card c1; ….
return 0;}
Global
![Page 4: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/4.jpg)
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
1CLUBS0
Card::Card(): rank(NO_RANK), suit(NO_SUIT) {}
b.rank NO_RANKNO_SUIT
3CLUBSb.suit
Card b; b=a;
Card& Card::operator= (const Card& other) {
rank= other.rank;
suit = other.suit;
}
Card::~Card() {}
0x12345678
![Page 5: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/5.jpg)
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 HeartsGame3. Return the address of the newly created
object
0x40123456
0x40123456
0x40123456
![Page 6: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/6.jpg)
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);
![Page 7: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/7.jpg)
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;}
![Page 8: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/8.jpg)
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”
pplayers TedSueJoeBob
p
tempTedSue
dest
Ken
JoeBob
Could throw exceptions
temp won’t be deleted if any exception is thrown
![Page 9: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/9.jpg)
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)
![Page 10: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/10.jpg)
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.
![Page 11: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/11.jpg)
RAII Utility Classes
template <class T> 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 T> class vector { T* ptr; size_t sz;public : vector() :ptr(0), sz(0) {} ~ vector () { delete ptr[]; } … void swap(vector& );}
![Page 12: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/12.jpg)
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> 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();
![Page 13: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/13.jpg)
Stock Smart Pointers
Boost (www.boost.org) scoped_ptr shared_ptr weak_ptr
std auto_ptr
![Page 14: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/14.jpg)
boost::scoped_ptr
Used for a single object, not for array Noncopyable
scoped_ptr<Game> game1(new BridgeGame); // OK
scope_ptr<Game> game2(game1); // Won’t compile
scoped_ptr<Game> game3; // OK
game3 = game1; // Won’t compile
game3.reset(new BridgeGame); // OK
game3.swap(game1); // OK
Useful to implement pointer to implementation (pimple) idiom.
![Page 15: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/15.jpg)
C++ Pimple idiom(Conceptual View)
+method1()+method2()
<<interface>>Foo
+method1()+method2()
-state
<<implementation class>>FooImpl
1
-pimpl
1
pimpl->method1();
![Page 16: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/16.jpg)
C++ Pimple idiom(implementation View)
/// Foo.h#include <boost/scoped_ptr.hpp>
struct FooImpl; // forward declarationclass Foo { using namespace boost; scoped_ptr<FooImpl> pimpl; public: Foo(); void method1();};
/// Foo.cc#include “Foo.h”
struct FooImpl { int state; …};
Foo::Foo() : pimpl(new FooImpl) {}
void Foo::method1() { ++ pimpl->state; …}
![Page 17: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/17.jpg)
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
![Page 18: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/18.jpg)
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<Game> makeGame(const char* name) {if (strcmp(name, “bridge”) ==0)
return auto_ptr<Game>(new BridgeGame); else if (strcmp(name, “hearts”) == 0)
return auto_ptr<Game>(new HeartsGame); return auto_ptr<Game>();}
![Page 19: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/19.jpg)
boost:shared_ptr• Reference counting semantics.• Simplest form of garbage collection
a : share_ptr<Foo>
ptrpcount :Foo
1 : int
-ptr : T*-pcount : int*
shared_ptr
T
Class ViewObject View
b : share_ptr<Foo>
ptrpcount
shared_ptr<Foo> a(new Foo);shared_ptr<Foo> b = a;
2 : int0 : int
![Page 20: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/20.jpg)
Reference Counting and Cyclic Dependency Problem
Deparment Course
1*
belongs to
offers
class Department { vector<share_ptr<Course> > courses; }
class Course { share_ptr<Course> department; }
![Page 21: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/21.jpg)
Reference Counting and Cyclic Dependency Problem
void fun() { shared_ptr<Department> cse(new Department); shared_ptr<Course> cse332(new Course); cse332.department = cse; cse.courses.push_back(cse332);}
csecse332
: Department : Course
1 : int 1 : int
courses department
2 : int
courses[0]
2 : int
![Page 22: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/22.jpg)
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<shared_ptr<Course> > courses;};
Class Course { weak_ptr<Department> department;};
void fun() { shared_ptr<Department> cse(new Department); shared_ptr<Course> cse332(new Course); cse332.department = cse; cse.courses.push_back(cse332);}
The reference count is not incremented
![Page 23: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/23.jpg)
Collection of Objects Player* players = new Player[size];
Need explicit delete statement for players array vector<Player> players;
Expensive Player object copying vector<Player*> players;
May require explicit delete statement for each individual Player object
vector<scoped_ptr<Player> > and vector<auto_ptr<Player> > 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
![Page 24: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/24.jpg)
Collection of Objects
vector<boost::shared_ptr<Player> > players Ownership to Player objects are not exclusive Comparing to vector<Player*>, it incurs small overhead for
reference counting. No need for explicit delete statement.
boost::ptr_vector<Player> 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.
![Page 25: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/25.jpg)
Preferred Form for Object Collections
vector<int>, vector<Card> Contained objects are cheap to copy
ptr_vector<Player>, ptr_vector<Game> Contained objects are expensive to copy or
polymorphic. vector<shared_ptr<Player> > or
vector<share_ptr<Game> > The ownership of the contained object cannot be
exclusively held.
![Page 26: Writing Correct C++ Programs without “delete” Huang-Ming Huang CSE332 Guest Lecture Washington University in St. Louis](https://reader036.vdocuments.net/reader036/viewer/2022062421/56649f4e5503460f94c7007e/html5/thumbnails/26.jpg)
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.