Upload
deepan-dhanakodi
View
16
Download
1
Tags:
Embed Size (px)
DESCRIPTION
boot
Citation preview
Or: How I Learned To Stop Or: How I Learned To Stop WorryingWorrying
And Love Resource ManagementAnd Love Resource Management
Stephan T. LavavejStephan T. LavavejVisual C++ Libraries DeveloperVisual C++ Libraries Developer
1Version 1.1 - January 18, 2008
Boost ComponentsBoost Components shared_ptrshared_ptr (and (and weak_ptrweak_ptr)) mem_fn()mem_fn(), , bind()bind(), and , and functionfunction regexregex <random><random> "Containers": "Containers": tupletuple, , arrayarray, , unordered_setunordered_set (etc.) (etc.) <type_traits><type_traits> reference_wrapperreference_wrapper
C99 Compatibility (C99 Compatibility (<cstdint><cstdint>, etc.), etc.) Special Math Functions (Special Math Functions (riemann_zeta()riemann_zeta(), ,
etc.)etc.)
2Version 1.1 - January 18, 2008
Effective C++, Third EditionEffective C++, Third Edition (2005) by Scott (2005) by Scott Meyers:Meyers:
""shared_ptrshared_ptr may be the most widely useful may be the most widely useful component in TR1."component in TR1."
C++ Coding StandardsC++ Coding Standards (2005) by Herb (2005) by Herb Sutter and Andrei Alexandrescu:Sutter and Andrei Alexandrescu:
"Store only values and smart pointers in "Store only values and smart pointers in containers. To this we add: If you use containers. To this we add: If you use [Boost] and [C++TR104] for nothing else, [Boost] and [C++TR104] for nothing else, use them for use them for shared_ptrshared_ptr."."
3Version 1.1 - January 18, 2008
A templated...A templated... non-intrusive...non-intrusive... deterministically reference-counted...deterministically reference-counted... smart pointer...smart pointer... (to a single object)...(to a single object)... that works with polymorphic types...that works with polymorphic types... incomplete types...incomplete types... and STL containers (sequence and and STL containers (sequence and
associative)!associative)!
4Version 1.1 - January 18, 2008
Generalizing over types without Generalizing over types without forgetting typesforgetting types
shared_ptr<T>shared_ptr<T> "shared pointer to "shared pointer to TT""
shared_ptr<const T>shared_ptr<const T> "shared pointer to "shared pointer to const Tconst T""
const shared_ptr<const T>const shared_ptr<const T> ""constconst shared pointer to shared pointer to const Tconst T""
"Look, Mom! No backwards reading!""Look, Mom! No backwards reading!"
5Version 1.1 - January 18, 2008
You can instantiate You can instantiate shared_ptr<T>shared_ptr<T> without without modifying the definition of modifying the definition of TT
(That is, the reference count is not embedded)(That is, the reference count is not embedded) Huge usability benefit for minimal perf costHuge usability benefit for minimal perf cost Works with built-in types: Works with built-in types: shared_ptr<int>shared_ptr<int> You can begin using You can begin using shared_ptrshared_ptr in your in your
codebase without having to modify your codebase without having to modify your existing typesexisting types
You can stop using You can stop using shared_ptrshared_ptr for a type for a type without having to rip machinery out of itwithout having to rip machinery out of it
A type can be sometimes held by A type can be sometimes held by shared_ptrshared_ptr and sometimes contained by another typeand sometimes contained by another type
6Version 1.1 - January 18, 2008
DeterministicDeterministic shared_ptrshared_ptrs collectively share ownership of an s collectively share ownership of an
objectobject When the last When the last shared_ptrshared_ptr dies, the object dies... dies, the object dies... Immediately!Immediately!
Reference-CountedReference-Counted Directed acyclic graphs of Directed acyclic graphs of shared_ptrshared_ptrs to objects s to objects
containing containing shared_ptrshared_ptrs to other objects... are s to other objects... are OKAYOKAY
Cycles of Cycles of shared_ptrshared_ptrs are s are LEAKTROCITYLEAKTROCITY Someone else has to ultimately own youSomeone else has to ultimately own you You can't own yourself!You can't own yourself!
7Version 1.1 - January 18, 2008
SmartSmart Unlike Unlike auto_ptrauto_ptr, which was a stupid smart pointer, which was a stupid smart pointer Sane copy constructor and copy assignment Sane copy constructor and copy assignment
operatoroperator Behaves like an ordinary value typeBehaves like an ordinary value type Pass and return by value and by reference as usualPass and return by value and by reference as usual Plays nice with Plays nice with constconst
PointerPointer Overloads Overloads operator*()operator*() and and operator->()operator->() Conversion function to Conversion function to unspecified-bool-typeunspecified-bool-type if (sp)if (sp) will compile, will compile, sp * 5sp * 5 will not compile will not compile
No jagged metal edges!No jagged metal edges!
8Version 1.1 - January 18, 2008
A single object, not an array!A single object, not an array! If you If you newnew up an array and hand it to a up an array and hand it to a shared_ptrshared_ptr:: It will compileIt will compile It will trigger It will trigger UNDEFINED BEHAVIORUNDEFINED BEHAVIOR Which might mean Which might mean LEAKTROCITYLEAKTROCITY or or CRASHTROCITYCRASHTROCITY
If you need...If you need... a container: a container: vectorvector a shared container: a shared container: shared_ptr<vector<T> >shared_ptr<vector<T> > less overhead: less overhead: shared_arrayshared_array (in Boost, but not (in Boost, but not
TR1)TR1) or perhaps: or perhaps: shared_ptr<array<T> >shared_ptr<array<T> > (in TR1) (in TR1)
Custom deleters are insufficient (no Custom deleters are insufficient (no op[]op[]))9Version 1.1 - January 18, 2008
shared_ptr<Derived>shared_ptr<Derived> is convertible to is convertible to shared_ptr<Base>shared_ptr<Base>
Works fine, doesn't screw up the reference Works fine, doesn't screw up the reference countcount
Need to convert back?Need to convert back? static_pointer_cast<Derived>(spBase)static_pointer_cast<Derived>(spBase) dynamic_pointer_cast<Derived>(spBase)dynamic_pointer_cast<Derived>(spBase)
While we're at it...While we're at it... const_pointer_cast<T>(spConstT)const_pointer_cast<T>(spConstT)
None of these throw exceptions!None of these throw exceptions! There is no There is no reinterpret_pointer_castreinterpret_pointer_cast Note: Note: shared_ptrshared_ptr itself is not polymorphic itself is not polymorphic
10Version 1.1 - January 18, 2008
struct X;struct X; void fxn(const shared_ptr<X>& p);void fxn(const shared_ptr<X>& p); However, However, XX must be complete by the time must be complete by the time
that you instantiate certain member that you instantiate certain member functions of functions of shared_ptr<X>shared_ptr<X>, such as its , such as its constructor from constructor from X *X *
Reason: If the constructor fails (e.g. to Reason: If the constructor fails (e.g. to allocate memory for a reference count), it allocate memory for a reference count), it must delete the must delete the XX before throwing, and before throwing, and deletion requires complete types in generaldeletion requires complete types in general
11Version 1.1 - January 18, 2008
auto_ptrauto_ptr is inherently an enemy of the STL is inherently an enemy of the STL The STL loves ordinary value typesThe STL loves ordinary value types auto_ptrauto_ptr does not behave like an ordinary value does not behave like an ordinary value
typetype Whoever wins, we loseWhoever wins, we lose
shared_ptr is the STL's best friendshared_ptr is the STL's best friend shared_ptrshared_ptr behaves like an ordinary value type behaves like an ordinary value type In fact, In fact, shared_ptrshared_ptr wraps non-values like wraps non-values like
noncopyable and polymorphic types in value's noncopyable and polymorphic types in value's clothingclothing
vector<shared_ptr<Socket> >vector<shared_ptr<Socket> > vector<shared_ptr<Base> >vector<shared_ptr<Base> > Comes with Comes with operator<()operator<() for use in sets and maps for use in sets and maps
12Version 1.1 - January 18, 2008
Policy CustomizablePolicy Customizable Loki smart pointers are extremely customizableLoki smart pointers are extremely customizable Ownership: refcount, reflink, destructive, etc.Ownership: refcount, reflink, destructive, etc. Implicit conversion to raw pointer: allow, disallowImplicit conversion to raw pointer: allow, disallow And so forthAnd so forth Policies are encoded in the smart pointer's type, Policies are encoded in the smart pointer's type,
preventing interoperability (sometimes, but not preventing interoperability (sometimes, but not always, solvable with ninja template heroics)always, solvable with ninja template heroics)
shared_ptrshared_ptr chooses good policies and bakes chooses good policies and bakes them inthem in
Deleters and allocators Deleters and allocators areare customizable, as they customizable, as they don't affect the typedon't affect the type
13Version 1.1 - January 18, 2008
Containers of Containers of shared_ptrshared_ptr vector<shared_ptr<NoncopyableResource> >vector<shared_ptr<NoncopyableResource> > vector<shared_ptr<PolymorphicBase> >vector<shared_ptr<PolymorphicBase> > Any other STL/TR1 containers, especially caches:Any other STL/TR1 containers, especially caches: map<Key, shared_ptr<NoncopyableResource> >map<Key, shared_ptr<NoncopyableResource> >
Passing around copyable but "heavy" objects Passing around copyable but "heavy" objects efficiently (a simple version of move efficiently (a simple version of move semantics)semantics)
Superseding Superseding auto_ptrauto_ptr Holding dynamically allocated objects at local Holding dynamically allocated objects at local
scopescope Holding multiple dynamically allocated objects as Holding multiple dynamically allocated objects as
members (what does this mean? See next slide...)members (what does this mean? See next slide...)
14Version 1.1 - January 18, 2008
Behold Behold LEAKTROCITYLEAKTROCITY::Foo::Foo() : m_p(0), m_q(0) {Foo::Foo() : m_p(0), m_q(0) {
m_p = new X;m_p = new X;
m_q = new Y;m_q = new Y;
}}
Foo::~Foo() {Foo::~Foo() {
delete m_p;delete m_p;
delete m_q;delete m_q;
}}
With With shared_ptrshared_ptr, this doesn't leak:, this doesn't leak:Foo::Foo() : m_sp(new X), m_sq(new Y) { }Foo::Foo() : m_sp(new X), m_sq(new Y) { }
// Implicitly defined dtor is OK for these members// Implicitly defined dtor is OK for these members
15Version 1.1 - January 18, 2008
Guidelines:Guidelines: All occurrences of All occurrences of new[]new[]//delete[]delete[] should already should already
have been replaced with have been replaced with vectorvector All occurrences of All occurrences of newnew should immediately be given should immediately be given
to a named to a named shared_ptrshared_ptr All occurrences of All occurrences of deletedelete should vanish should vanish
Exceptions:Exceptions: When implementing custom data structures like When implementing custom data structures like
trees that can't be composed from the STL and TR1trees that can't be composed from the STL and TR1 When performance is absolutely criticalWhen performance is absolutely critical
Manual resource management is extremely Manual resource management is extremely difficult to do safely; consider it to be a last difficult to do safely; consider it to be a last resortresort
16Version 1.1 - January 18, 2008
shared_ptr<string> sp(new string("meow"));shared_ptr<string> sp(new string("meow"));
cout << *sp << endl;cout << *sp << endl;
cout << sp->size() << endl;cout << sp->size() << endl;
Prints:Prints:meowmeow
44
Each Each newnew object is immediately given to a object is immediately given to a shared_ptrshared_ptr
Each Each deletedelete statement vanishes from statement vanishes from the sourcethe source
17Version 1.1 - January 18, 2008
shared_ptr<string> sp shared_ptr<string> sp == new string("meow"); new string("meow");
Compiler error (after substitution):Compiler error (after substitution):error C2440: 'initializing' : cannot convert from error C2440: 'initializing' : cannot convert from
'std::string *' to 'std::tr1::shared_ptr<std::string>''std::string *' to 'std::tr1::shared_ptr<std::string>'
Constructor for class 'std::tr1::shared_ptr<std::string>' Constructor for class 'std::tr1::shared_ptr<std::string>' is declared 'explicit'is declared 'explicit'
Direct-initialization can use an explicit ctorDirect-initialization can use an explicit ctor Copy-initialization performs conversion: Copy-initialization performs conversion:
explicit ctors are unavailableexplicit ctors are unavailable shared_ptrshared_ptr acquires ownership explicitly acquires ownership explicitly
18Version 1.1 - January 18, 2008
shared_ptr<int> a;shared_ptr<int> a;shared_ptr<int> b(new int(137));shared_ptr<int> b(new int(137));cout << (a ? "a" : "X") << endl;cout << (a ? "a" : "X") << endl;if (b) {if (b) { cout << "b" << endl;cout << "b" << endl;} else {} else { cout << "Y" << endl;cout << "Y" << endl;}} Prints:Prints:XXbb Also: Also: if (!sp)if (!sp), , if (sp && blah)if (sp && blah), , if (sp || blah)if (sp || blah)
19Version 1.1 - January 18, 2008
auto_ptrauto_ptr: Not directly testable. Instead, : Not directly testable. Instead, you must test you must test if (ap.get())if (ap.get()) auto_ptrauto_ptr is deprecated in C++0x! is deprecated in C++0x!
unique_ptrunique_ptr: Has a conversion function to : Has a conversion function to unspecified-bool-typeunspecified-bool-type just like just like shared_ptrshared_ptr unique_ptrunique_ptr is the C++0x replacement for is the C++0x replacement for auto_ptrauto_ptr (not part of TR1) (not part of TR1)
weak_ptrweak_ptr: Not directly testable. Instead, : Not directly testable. Instead, you must test you must test if (!wp.expired())if (!wp.expired()) weak_ptrweak_ptr usage is covered later in this usage is covered later in this
presentationpresentation
20Version 1.1 - January 18, 2008
shared_ptr<int> foo(int n) {shared_ptr<int> foo(int n) {
shared_ptr<int> r(new int(n));shared_ptr<int> r(new int(n));
*r += 5;*r += 5;
return r;return r;
}}
int main() {int main() {
shared_ptr<int> p = foo(3);shared_ptr<int> p = foo(3);
cout << *p << endl;cout << *p << endl;
}}
Prints:Prints:88
21Version 1.1 - January 18, 2008
shared_ptr<int> a(new int(1));shared_ptr<int> a(new int(1));shared_ptr<int> b = a;shared_ptr<int> b = a;*a += 6;*a += 6;cout << *a << ", " << *b << endl;cout << *a << ", " << *b << endl;a.reset();a.reset();cout << "a: " << (a ? "owns" : "empty") << endl;cout << "a: " << (a ? "owns" : "empty") << endl;cout << "b: " << (b ? "owns" : "empty") << endl;cout << "b: " << (b ? "owns" : "empty") << endl;cout << *b << endl;cout << *b << endl; Prints:Prints:7, 77, 7a: emptya: emptyb: ownsb: owns77
22Version 1.1 - January 18, 2008
shared_ptr<int> frob(new int(100));shared_ptr<int> frob(new int(100));
shared_ptr<const int> look = frob;shared_ptr<const int> look = frob;
cout << *look << endl;cout << *look << endl;
*frob /= 2;*frob /= 2;
cout << *look << endl;cout << *look << endl;
// *look /= 2;// *look /= 2;
Prints:Prints:100100
5050
Uncomment the last line to get this compiler Uncomment the last line to get this compiler error:error:
error C3892: 'look' : you cannot assign to a variable error C3892: 'look' : you cannot assign to a variable that is constthat is const
23Version 1.1 - January 18, 2008
cats.txt:cats.txt:AbyssinianAbyssinianBalineseBalineseChesireChesireDevon RexDevon Rex dogs.txt:dogs.txt:AlsatianAlsatianBeagleBeagleCollieCollie people.txt:people.txt:AlanAlanBjarneBjarneCharlesCharlesDonaldDonaldEdsgerEdsger
24Version 1.1 - January 18, 2008
queue<shared_ptr<ifstream> > q;queue<shared_ptr<ifstream> > q;
for (string s; getline(cin, s); ) {for (string s; getline(cin, s); ) { shared_ptr<ifstream> p(new ifstream(s.c_str()));shared_ptr<ifstream> p(new ifstream(s.c_str())); q.push(p);q.push(p);}}
while (!q.empty()) {while (!q.empty()) { string s;string s;
if (getline(*q.front(), s)) {if (getline(*q.front(), s)) { cout << s << endl;cout << s << endl; q.push(q.front());q.push(q.front()); }}
q.pop();q.pop();}}
25Version 1.1 - January 18, 2008
cats.txtcats.txtdogs.txtdogs.txtpeople.txtpeople.txt^Z^ZAbyssinianAbyssinianAlsatianAlsatianAlanAlanBalineseBalineseBeagleBeagleBjarneBjarneChesireChesireCollieCollieCharlesCharlesDevon RexDevon RexDonaldDonaldEdsgerEdsger
26Version 1.1 - January 18, 2008
class Animal {class Animal {
public:public:
explicit Animal(const string& name) : m_name(name) { }explicit Animal(const string& name) : m_name(name) { }
string noise() const {string noise() const {
return m_name + " says " + noise_impl();return m_name + " says " + noise_impl();
}}
virtual ~Animal() { }virtual ~Animal() { }
private:private:
Animal(const Animal&);Animal(const Animal&);
Animal& operator=(const Animal&);Animal& operator=(const Animal&);
virtual string noise_impl() const = 0;virtual string noise_impl() const = 0;
string m_name;string m_name;
};};
27Version 1.1 - January 18, 2008
class Cat : public Animal {class Cat : public Animal {
public: explicit Cat(const string& name) : Animal(name) { }public: explicit Cat(const string& name) : Animal(name) { }
private: virtual string noise_impl() const { return "meow"; }private: virtual string noise_impl() const { return "meow"; }
};};
class Dog : public Animal {class Dog : public Animal {
public: explicit Dog(const string& name) : Animal(name) { }public: explicit Dog(const string& name) : Animal(name) { }
private: virtual string noise_impl() const { return "woof"; }private: virtual string noise_impl() const { return "woof"; }
};};
class Pig : public Animal {class Pig : public Animal {
public: explicit Pig(const string& name) : Animal(name) { }public: explicit Pig(const string& name) : Animal(name) { }
private: virtual string noise_impl() const { return "oink"; }private: virtual string noise_impl() const { return "oink"; }
};};
28Version 1.1 - January 18, 2008
vector<shared_ptr<Animal> > v;vector<shared_ptr<Animal> > v;
shared_ptr<Cat> c(new Cat("Garfield"));shared_ptr<Cat> c(new Cat("Garfield"));
shared_ptr<Dog> d(new Dog("Odie"));shared_ptr<Dog> d(new Dog("Odie"));
shared_ptr<Pig> p(new Pig("Orson"));shared_ptr<Pig> p(new Pig("Orson"));
v.push_back(c);v.push_back(c);
v.push_back(d);v.push_back(d);
v.push_back(p);v.push_back(p);
transform(v.begin(), v.end(),transform(v.begin(), v.end(),
ostream_iterator<string>(cout, "\n"),ostream_iterator<string>(cout, "\n"),
mem_fn(&Animal::noise));mem_fn(&Animal::noise));
29Version 1.1 - January 18, 2008
Garfield says meowGarfield says meow
Odie says woofOdie says woof
Orson says oinkOrson says oink
30Version 1.1 - January 18, 2008
shared_ptr<Cat> p(new Cat("Peppermint"));shared_ptr<Cat> p(new Cat("Peppermint"));
shared_ptr<Cat> c;shared_ptr<Cat> c;
shared_ptr<Animal> a;shared_ptr<Animal> a;
c = p;c = p;
a = p;a = p;
cout << c->noise() << endl;cout << c->noise() << endl;
cout << a->noise() << endl;cout << a->noise() << endl;
Prints:Prints:Peppermint says meowPeppermint says meow
Peppermint says meowPeppermint says meow
31Version 1.1 - January 18, 2008
shared_ptr<Cat> p(new Cat("Peppermint"));shared_ptr<Cat> p(new Cat("Peppermint"));
shared_ptr<Animal> a = p;shared_ptr<Animal> a = p;
cout << (p == a ? "same" : "different") << endl;cout << (p == a ? "same" : "different") << endl;
Prints:Prints:samesame
32Version 1.1 - January 18, 2008
shared_ptr<Animal> a(new Cat("Bucky"));shared_ptr<Animal> a(new Cat("Bucky"));
cout << a->noise() << endl;cout << a->noise() << endl;
a.reset(new Dog("Satchel"));a.reset(new Dog("Satchel"));
cout << a->noise() << endl;cout << a->noise() << endl;
Prints:Prints:Bucky says meowBucky says meow
Satchel says woofSatchel says woof
33Version 1.1 - January 18, 2008
shared_ptrshared_ptr has both member and free has both member and free swap()swap() Just like STL containersJust like STL containers
swap()swap() is intended to be implemented is intended to be implemented efficientlyefficiently In VC9 TR1, it is implemented efficientlyIn VC9 TR1, it is implemented efficiently "Efficient" means not modifying the refcounts"Efficient" means not modifying the refcounts
This is This is GOODGOOD::shared_ptr<string> a(new string("meow")); // meow: 1shared_ptr<string> a(new string("meow")); // meow: 1
shared_ptr<string> b(new string("purr")); // purr: 1shared_ptr<string> b(new string("purr")); // purr: 1
a.swap(b); // meow: 1, purr: 1a.swap(b); // meow: 1, purr: 1
swap(a, b); // meow: 1, purr: 1swap(a, b); // meow: 1, purr: 1
34Version 1.1 - January 18, 2008
Behold Behold SLOWTROCITYSLOWTROCITY::shared_ptr<string> a(new string("meow")); // meow: 1shared_ptr<string> a(new string("meow")); // meow: 1shared_ptr<string> b(new string("purr")); // purr: 1shared_ptr<string> b(new string("purr")); // purr: 1{{ shared_ptr<string> t(a); // meow: 2 INCMEOWshared_ptr<string> t(a); // meow: 2 INCMEOW a = b; // meow: 1, purr: 2 DECMEOW, INCPURRa = b; // meow: 1, purr: 2 DECMEOW, INCPURR b = t; // meow: 2, purr: 1 INCMEOW, DECPURRb = t; // meow: 2, purr: 1 INCMEOW, DECPURR} // meow: 1 DECMEOW } // meow: 1 DECMEOW This unnecessarily modifies the refcounts 6 This unnecessarily modifies the refcounts 6
timestimes Even worse, this dereferences pointers 6 timesEven worse, this dereferences pointers 6 times Even worse, this uses interlocked operations 6 Even worse, this uses interlocked operations 6
timestimes Solution: Just use Solution: Just use swap()swap()
35Version 1.1 - January 18, 2008
Correct:Correct:shared_ptr<int> owning(new int(47));shared_ptr<int> owning(new int(47));
int * raw = owning.get();int * raw = owning.get();
Incorrect:Incorrect:shared_ptr<int> owning(new int(47));shared_ptr<int> owning(new int(47));
int * raw = owning;int * raw = owning;
Compiler error (after substitution):Compiler error (after substitution):error C2440: 'initializing' : cannot convert from error C2440: 'initializing' : cannot convert from
'std::tr1::shared_ptr<int>' to 'int *''std::tr1::shared_ptr<int>' to 'int *'
No user-defined-conversion operator No user-defined-conversion operator available that can perform this conversion, or available that can perform this conversion, or the operator cannot be calledthe operator cannot be called
36Version 1.1 - January 18, 2008
Which statements contain Which statements contain LEAKTROCITYLEAKTROCITY??f1(shared_ptr<Foo>(new Foo(args)));f1(shared_ptr<Foo>(new Foo(args)));
f2(shared_ptr<Foo>(new Foo(args)), g());f2(shared_ptr<Foo>(new Foo(args)), g());
f3(shared_ptr<Foo>(new Foo(args)),f3(shared_ptr<Foo>(new Foo(args)),
shared_ptr<Bar>(new Bar(args)));shared_ptr<Bar>(new Bar(args)));
Solution: Give each Solution: Give each shared_ptrshared_ptr a name a nameshared_ptr<Foo> foo(new Foo(args));shared_ptr<Foo> foo(new Foo(args));
shared_ptr<Bar> bar(new Bar(args));shared_ptr<Bar> bar(new Bar(args));
f1(foo);f1(foo);
f2(foo, g());f2(foo, g());
f3(foo, bar);f3(foo, bar);
37Version 1.1 - January 18, 2008
void foo() {void foo() {
shared_ptr<int> sp(new int(1729));shared_ptr<int> sp(new int(1729));
int * raw = sp.get();int * raw = sp.get();
delete raw;delete raw;
}}
Result: Result: DOUBLE DELETIONDOUBLE DELETION Unlike Unlike auto_ptrauto_ptr, , shared_ptrshared_ptr has no has no release()release() member function member function
get()get() returns a non-owning raw pointer returns a non-owning raw pointer
38Version 1.1 - January 18, 2008
struct Ansible {struct Ansible { shared_ptr<Ansible> get_shared() {shared_ptr<Ansible> get_shared() { shared_ptr<Ansible> ret(this);shared_ptr<Ansible> ret(this); return ret;return ret; }}};};
int main() {int main() { shared_ptr<Ansible> a(new Ansible);shared_ptr<Ansible> a(new Ansible); Ansible& r = *a;Ansible& r = *a; shared_ptr<Ansible> b = r.get_shared();shared_ptr<Ansible> b = r.get_shared();}} Result: Result: DOUBLE DELETIONDOUBLE DELETION
39Version 1.1 - January 18, 2008
struct Ansiblestruct Ansible
: public enable_shared_from_this<Ansible> { };: public enable_shared_from_this<Ansible> { };
int main() {int main() {
shared_ptr<Ansible> a(new Ansible);shared_ptr<Ansible> a(new Ansible);
Ansible& r = *a;Ansible& r = *a;
shared_ptr<Ansible> b = r.shared_from_this();shared_ptr<Ansible> b = r.shared_from_this();
}}
aa and and bb share ownership, as if: share ownership, as if:shared_ptr<Ansible> b = a;shared_ptr<Ansible> b = a;
40Version 1.1 - January 18, 2008
shared_ptr<int> a(new int(2161));shared_ptr<int> a(new int(2161));
shared_ptr<const int> b(a);shared_ptr<const int> b(a);
shared_ptr<int> c(const_cast<int *>(b.get()));shared_ptr<int> c(const_cast<int *>(b.get()));
Result: Result: DOUBLE DELETIONDOUBLE DELETION Solution: Use Solution: Use const_pointer_castconst_pointer_castshared_ptr<int> c(const_pointer_cast<int>(b));shared_ptr<int> c(const_pointer_cast<int>(b));
static_pointer_caststatic_pointer_cast, , dynamic_pointer_castdynamic_pointer_cast, and , and const_pointer_castconst_pointer_cast exist for exist for correctness, not conveniencecorrectness, not convenience
41Version 1.1 - January 18, 2008
void observe(const weak_ptr<int>& wp) {void observe(const weak_ptr<int>& wp) { shared_ptr<int> t = wp.lock();shared_ptr<int> t = wp.lock(); cout << (t ? *t : 2010) << endl;cout << (t ? *t : 2010) << endl;}}
weak_ptr<int> wp;weak_ptr<int> wp;{{ shared_ptr<int> sp(new int(1969));shared_ptr<int> sp(new int(1969)); wp = sp;wp = sp; observe(wp);observe(wp);}}observe(wp);observe(wp); Prints:Prints:1969196920102010
42Version 1.1 - January 18, 2008
Read: Any operation that can be performed to a Read: Any operation that can be performed to a const shared_ptrconst shared_ptr (copying, dereferencing, etc.) (copying, dereferencing, etc.)
Write: Any operation that cannot be performed to Write: Any operation that cannot be performed to a a const shared_ptrconst shared_ptr (assigning, resetting, (assigning, resetting, swapping, etc.)swapping, etc.)
Destruction counts as a writeDestruction counts as a write Multiple threads can simultaneously read a single Multiple threads can simultaneously read a single
shared_ptrshared_ptr object object Multiple threads can simultaneously read/write Multiple threads can simultaneously read/write
different different shared_ptrshared_ptr objects objects Even when the objects are copies that share ownershipEven when the objects are copies that share ownership
Anything else triggers Anything else triggers UNDEFINED BEHAVIORUNDEFINED BEHAVIOR Both VC9 TR1 and Boost provide these guaranteesBoth VC9 TR1 and Boost provide these guarantees
43Version 1.1 - January 18, 2008
shared_ptrshared_ptr's ctor and 's ctor and reset()reset() can take can take an additional "deleter" argumentan additional "deleter" argument
A deleter is a functor that will be called A deleter is a functor that will be called with the stored raw pointer to release the with the stored raw pointer to release the owned objectowned object
Simplest example: Simplest example: free()free() The deleter's actual type is forgottenThe deleter's actual type is forgotten
As if through inheritanceAs if through inheritance The deleter stays with the owned objectThe deleter stays with the owned object
NOTNOT with the with the shared_ptrshared_ptr
44Version 1.1 - January 18, 2008
Allocator support is a C++0x feature (not in TR1)Allocator support is a C++0x feature (not in TR1) Implemented by VC9 TR1 and Boost 1.35Implemented by VC9 TR1 and Boost 1.35
shared_ptr<T>shared_ptr<T> gains a three-arg ctor and gains a three-arg ctor and reset()reset() Taking Taking (T *, Deleter, Allocator)(T *, Deleter, Allocator)
The third argument:The third argument: Must be an STL allocator (20.1.5 lists the requirements)Must be an STL allocator (20.1.5 lists the requirements) Will be rebound (you can pass Will be rebound (you can pass YourAlloc<int>YourAlloc<int>)) Will be used to allocate/deallocate the reference countWill be used to allocate/deallocate the reference count
The allocator's actual type is forgottenThe allocator's actual type is forgotten As if through inheritanceAs if through inheritance
The allocator stays with the owned objectThe allocator stays with the owned object NOTNOT with the with the shared_ptrshared_ptr
45Version 1.1 - January 18, 2008
shared_ptrshared_ptr and and weak_ptrweak_ptr contain two raw pointers: contain two raw pointers: Pointer to owned object (used for dereferencing)Pointer to owned object (used for dereferencing) Pointer to Pointer to _Ref_count_base_Ref_count_base
_Ref_count_base contains:_Ref_count_base contains: Pointer to owned object (used for deleting)Pointer to owned object (used for deleting) 32-bit strong refcount (# of 32-bit strong refcount (# of shared_ptrshared_ptrs)s) 32-bit weak refcount (# of 32-bit weak refcount (# of weak_ptrweak_ptrs + 1 for all s + 1 for all shared_ptrshared_ptrs)s)
When the strong refcount falls to zero:When the strong refcount falls to zero: _Ref_count_Ref_count deletedeletes the owned objects the owned object _Ref_count_d_Ref_count_d uses its stored deleter to nuke the owned object uses its stored deleter to nuke the owned object Both decrement the weak refcountBoth decrement the weak refcount
When the weak refcount falls to zero:When the weak refcount falls to zero: _Ref_count_Ref_count deletedeletes itselfs itself _Ref_count_d_Ref_count_d uses its stored allocator to nuke itself uses its stored allocator to nuke itself
Takeaways:Takeaways: shared_ptrshared_ptr is reasonably small is reasonably small Dereferencing a Dereferencing a shared_ptrshared_ptr involves involves ZERO OVERHEADZERO OVERHEAD
46Version 1.1 - January 18, 2008
Destructors encapsulate resource releaseDestructors encapsulate resource release Destructors are resource agnosticDestructors are resource agnostic
Memory, files, sockets, locks, textures, etc.Memory, files, sockets, locks, textures, etc. Destructors are executed deterministicallyDestructors are executed deterministically STL containers enabled "one owning many"STL containers enabled "one owning many" shared_ptrshared_ptr enables "many owning one" enables "many owning one"
Object CategoryObject Category Owned By TheirOwned By Their Destroyed Destroyed WhenWhen
Automatic Block Control Leaves Block
Data Members Parent Parent Dies
Elements Container Container Dies
Dynamically Allocated
shared_ptrs All shared_ptrs Die
47Version 1.1 - January 18, 2008
For more information, see:For more information, see: The TR1 draft: The TR1 draft: tinyurl.com/36lwqetinyurl.com/36lwqe The C++ Standard Library Extensions: A Tutorial The C++ Standard Library Extensions: A Tutorial
And ReferenceAnd Reference by Pete Becker: by Pete Becker: tinyurl.com/27jv8ntinyurl.com/27jv8n
Improving Improving shared_ptrshared_ptr For C++0x, Revision 2: For C++0x, Revision 2: tinyurl.com/2dlw3vtinyurl.com/2dlw3v Allocator Support, Aliasing Support, Object Creation, Allocator Support, Aliasing Support, Object Creation,
and Move Support were voted into the C++0x and Move Support were voted into the C++0x Working PaperWorking Paper
Improving Improving shared_ptrshared_ptr For C++0x, Revision 1: For C++0x, Revision 1: tinyurl.com/36cty7tinyurl.com/36cty7 Atomic Access and Cycle Collection are still plannedAtomic Access and Cycle Collection are still planned
48Version 1.1 - January 18, 2008