SlideShare a Scribd company logo
C++11 SMART POINTERS
@mine260309
• Overview
• shared_ptr
• unique_ptr
• weak_ptr
– Cyclic reference problem
– Enable shared from this
• Miscs
AGENDA
• std::shared_ptr
– shared ownership
• std::unique_ptr
– unique ownership
• std::weak_ptr
– No ownership
• NO std::intrusive_ptr
OVERVIEW
• boost::shared_ptr
– shared ownership
• boost::scoped_ptr
– unique ownership
• boost::weak_ptr
– No ownership
≈
Differences:
• Compiler (C++11 vs C++03)
• Move-Semantic
• std::unique_ptr supports transfer-of-ownership
• boost::scoped_ptr is neither copyable nor movable
• Array support (See details in Miscs)
std::shared_ptr
• Features
– share ownership
– reference count
– auto delete
– native inheritance
– cast
• Overhead
– Manager-Object*
– Managed-Object-T*
– Lock of increment/decrement of reference count (Thread safe)
SHARED_PTR
shared_ptr<T>
Manager
Object*
T*
Reference
Counted with
Lock
Object T
• Refer to objects allocated with new and can be deleted with
delete
• Create by new or make_shared
– shared_ptr<T> t(new T(…));
– shared_ptr<T> t(make_shared<T>(…));
• Try hard to avoid using raw pointers
– Mixing smart and built-in pointers can be hard to get right
• Then never explicitly call delete
RULES OF SHARED_PTR
• shared_ptr<T> t(new T(…));
– Two dynamic allocations
• shared_ptr<T> t(make_shared<T>(…));
– Single dynamic allocation
• Why?
– Manager-Object*
– Managed-Object-T*
• Prefer ::make_shared if a lof of shared_ptrs are created
MAKE_SHARED VS NEW
shared_ptr<T>
Manager
Object*
T*
Reference
Counted with
Lock
Object T
• http://ideone.com/aEFxlk
BASIC USE OF SHARED_PTR
std::shared_ptr<TClass> c2(new TClass(2)); // TClass 2
std::shared_ptr<TClass> c3 = std::make_shared<TClass>(3);
std::shared_ptr<TClass> c4; // Empty shared_ptr
c4.reset(new TClass(4)); // TClass: 4
if (c4) {
... // Do something
}
c4.reset(); // c4 becomes empty
if (c4) { // Now it returns false
... // Code does not go here
}
• Same as raw pointer
• http://ideone.com/jp4iCI
INHERITANCE OF SHARED_PTR
std::shared_ptr<TDerived> dp1(new TDerived);
std::shared_ptr<TBase> bp1 = dp1;
std::shared_ptr<TBase> bp2(dp1);
std::shared_ptr<TBase> bp3(new TDerived);
• Similar with raw pointer
– static_pointer_cast
– dynamic_pointer_cast
– const_pointer_cast
• Create a new shared_ptr!
• http://ideone.com/TdcPDl
CASTING SHARED_PTR
std::shared_ptr<TBase> bp1(new TDerived);
std::shared_ptr<const TBase> cbp(new TBase);
std::shared_ptr<TDerived> dp1 = std::static_pointer_cast<TDerived>(bp1);
std::shared_ptr<TDerived> dp2 = std::dynamic_pointer_cast<TDerived>(bp1);
std::shared_ptr<TBase> bp2 = std::const_pointer_cast<TBase>(cbp);
//std::shared_ptr<TDerived> d = static_cast<std::shared_ptr<TDerived>>(bp1);
// Compile error
std::unique_ptr
• Features
– Unique ownership
• Copy constructor and copy assignment = delete
– No reference count
– auto delete
– native inheritance
– No cast, or manually cast
• Overhead
– Nothing!
• Rules?
– The same as shared_ptr
UNIQUE_PTR
• new or std::move (transfer ownership)
• http://ideone.com/bxsFvC
BASIC USE OF UNIQUE_PTR
std::unique_ptr<TClass> c2(new TClass(2));
std::unique_ptr<TClass> c3; // Empty unique_ptr
//c3 = c2; // error: use of deleted function operator=()
c3 = std::move(c2); // unique_ptr has to be moved
// Now c2 owns nothing
// Note that return value of a function is a rvalue
std::unique_ptr<TClass> GetATClass() {
std::unique_ptr<TClass> c(new TClass(0));
return c; // same as `return std::move(c);`
}
c3 = GetATClass();
• Same as raw pointer
• http://ideone.com/FhgRi9
INHERITANCE OF UNIQUE_PTR
std::unique_ptr<TDerived> dp1(new TDerived);
std::unique_ptr<TBase> bp1 = std::move(dp1);
std::unique_ptr<TBase> bp2(std::move(bp1));
std::unique_ptr<TBase> bp3(new TDerived);
• Generally, do NOT cast
• Why no native cast?
– Cast makes a copy of the pointer
• But I do want to cast unique_ptr?
• http://ideone.com/F8CfIG
CAST(MANUALLY) OF UNIQUE_PTR
std::unique_ptr<TBase> bp1(new TDerived);
std::unique_ptr<TDerived> dp1(static_cast<TDerived*>(bp1.get()));
bp1.release(); // Now bp1 owns nothing
bp1 = std::move(dp1); // Transfer ownership to bp1 (inheritance)
std::unique_ptr<TDerived> dp2(dynamic_cast<TDerived*>(bp1.get()));
bp1.release(); // Now bp1 owns nothing
std::weak_ptr
• “Observe” the managed object
• Provide a shared_ptr when used
• Why?
– Solve cyclic reference of shared_ptr
– Helps to get a shared_ptr from “this”
WEAK_PTR
• http://ideone.com/tZ3ZhJ
BASIC USE OF WEAK_PTR
std::weak_ptr<TClass> w; // Empty weak_ptr
{
std::shared_ptr<TClass> c(new TClass); // TClass: -1
std::weak_ptr<TClass> w1(c); // Construct from shared_ptr
std::weak_ptr<TClass> w; // Empty weak_ptr
w = c;
std::weak_ptr<TClass> w3(w);
w3.reset(); // w3 becomes empty
w3 = w; // w3 points to the TClass as well
std::shared_ptr<TClass> c2 = w.lock(); //Get shared_ptr by weak_ptr
c2->IntValue = 1;
} // ~TClass: 1
std::shared_ptr<TClass> c3 = w.lock(); // c3 is empty shared_ptr
• http://ideone.com/KP8oSL
CYCLIC REFERENCE PROBLEM
class CyclicA {
public:
shared_ptr<CyclicB> b;
};
class CyclicB {
public:
shared_ptr<CyclicA> a;
};
void TestSharedPtrCyclicRef()
{
shared_ptr<CyclicA> a(new CyclicA);
shared_ptr<CyclicB> b(new CyclicB);
a->b = b;
b->a = a;
} // Neither a nor b is deleted
• http://ideone.com/KP8oSL
CYCLIC REFERENCE - FIX
class FixCyclicA {
public:
std::shared_ptr<FixCyclicB> b;
};
class FixCyclicB {
public:
std::weak_ptr<FixCyclicA> a;
};
void TestWeakPtrFixCyclicRef()
{
std::shared_ptr<FixCyclicA> a(new FixCyclicA);
std::shared_ptr<FixCyclicB> b(new FixCyclicB);
a->b = b;
b->a = a;
} // Both a and b are deleted
• How to get shared_ptr from class’s member function?
ENABLE SHARED FROM THIS - WHY
class TShareClass {
...
std::shared_ptr<TShareClass> GetThis() {
// how to achieve?
}
void CallFoo() {
Foo(GetThis());
}
}
void Foo(const std::shared_ptr<TShareClass>& s)
{
// Do something to s, e.g. s->xxx = xxx
}
• A wrong way
ENABLE SHARED FROM THIS – THE
WRONG WAY
class TShareClass {
...
std::shared_ptr<TShareClass> GetThis () {
return std::shared_ptr<TShareClass>(this);
} // This gets deleted after out-of-scope
}
{
std::shared_ptr<TShareClass> a(new TShareClass);
std::shared_ptr<TShareClass> temp = a.GetThis();
} // Deleted twice!
• One way to achieve: Add a weak_ptr
ENABLE SHARED FROM THIS – AN
ATTEMP
class TMyShareClass
{
public:
std::shared_ptr<TMyShareClass> GetThis() {
return MyWeakPtr.lock(); // Make sure MyWeakPtr is valid
}
std::weak_ptr<TMyShareClass> MyWeakPtr;
};
std::shared_ptr<TMyShareClass> c1(new TMyShareClass());
c1->MyWeakPtr = c1;
std::shared_ptr<TMyShareClass> c2 = c1->GetThis();
• C++11’s built-in enable_shared_from_this
• http://ideone.com/wRUj3U
ENABLE SHARED FROM THIS – A
DECENT WAY
class TShareClass : public std::enable_shared_from_this<TShareClass>
{
...
std::shared_ptr<TShareClass> GetThis() {
return shared_from_this();
}
};
std::shared_ptr<TShareClass> c1(new TShareClass());
std::shared_ptr<TShareClass> c2 = c1->GetThis();
• Do not call shared_from_this()from constructor
– weak_ptr is not valid yet in ctor
• Always create shared_ptr<T>, never create raw T*
• Consider make ctor/copy-ctors private and unique the
creation
– Prevent creating raw T in case of wrong usage
– Benefit from perfect forwarding
ENABLE SHARED FROM THIS – BE
CAREFUL
TShareClass* c1 = new TShareClass();
std::shared_ptr<TShareClass> c2 = c1->GetThis();
// Undefined behavior
// Throws exception 'std::bad_weak_ptr‘ on gcc 4.9.x
• Perfect creation of T (http://ideone.com/UyIPgb)
class TPerfectCtor : public std::enable_shared_from_this<TPerfectCtor>
{
private:
TPerfectCtor(int I = -1) = default;
TPerfectCtor(const TPerfectCtor& r) = default;
public:
template<typename ... T>
static std::shared_ptr<TPerfectCtor> Create(T&& ... all) {
return std::shared_ptr<TPerfectCtor>(
new TPerfectCtor(std::forward<T>(all)...));
}
std::shared_ptr<TPerfectCtor> GetThis() {
return shared_from_this();
}
};
// std::shared_ptr<TPerfectCtor> c1(new TPerfectCtor()); // compile error
std::shared_ptr<TPerfectCtor> c1 = TPerfectCtor::Create(); // TPerfectCtor: -1
std::shared_ptr<TPerfectCtor> c2 = TPerfectCtor::Create(2); // TPerfectCtor: 2
c2 = c1->GetThis(); // ~TPerfectCtor: 2
ENABLE SHARED FROM THIS – BEST
PRACTICE
Miscs
• Default, use unique_ptr
• Default, use unique_ptr in containers
– std::vector<std::unique_ptr<T>>
• If the object has shared ownership, use shared_ptr
• If the objects have shared ownership, use shared_ptr in
containers
– std::vector<std::shared_ptr<T>>
• Prefer to pass by const reference
– void Foo(const std::shared_ptr<T>& sp);
– void Foo(const std::unique_ptr<T>& up);
Do not write like below
– void Foo(std::shared_ptr<T>& sp); // Sometimes compile error
– Why? sp.reset(new Base) while sp is Derived
MISCS
MISCS – ARRAY SUPPORT
std::unique_ptr<T[]> ua(new T [5]); // OK
boost::scoped_ptr<T[]> ua(new T [5]); // Compile error
std::shared_ptr<T[]> ua(new T [5]); // Compile error
boost::shared_ptr<T []> a(new T [5]); // OK (since Boost 1.53)
// A custom deleter for array
std::shared_ptr<T> a(new T [5], std::default_delete<T[]>());
// OK, but access with a.get()[index]
// Never pass T[] to shared_ptr<T>
std::shared_ptr<T> a(new T [5]); // Crash
boost::shared_ptr<T> a(new T [5]); // Crash
• Suggested ways to use array in smart pointer
– std::unique_ptr<T[]>
– std::shared_ptr<T> with custom delete
– boost::shared_ptr<T[]> (Since Boost 1.53)
– boost::shared_array<T>
• Consider boost::ptr_vector<T> for vector of shared_ptr if
performance is critical
• http://ideone.com/n9lZJ2
MISCS – CONT.
• boost’s Pointer Container Library
– ptr_sequence_adapter
• ptr_vector
• ptr_list
• ptr_deque
• …
– associative_ptr_container
• ptr_set_adapter
• ptr_multiset_adapter
• ptr_map_adapter
• …
• boost::scoped_array
• boost::intrusive_ptr
FURTHER READINGS
Thank You!

More Related Content

PPTX
Smart pointers
PDF
Smart Pointers in C++
PPTX
What's New in C++ 11/14?
PDF
Smart Pointers
PPTX
PDF
[C++] The Curiously Recurring Template Pattern: Static Polymorphsim and Expre...
PPT
Smart Pointer in C++
PDF
C++11: Rvalue References, Move Semantics, Perfect Forwarding
Smart pointers
Smart Pointers in C++
What's New in C++ 11/14?
Smart Pointers
[C++] The Curiously Recurring Template Pattern: Static Polymorphsim and Expre...
Smart Pointer in C++
C++11: Rvalue References, Move Semantics, Perfect Forwarding

What's hot (20)

PPTX
PDF
C++11 & C++14
PPTX
C++ 11 Features
PDF
C++ references
PPTX
Lecture 3, c++(complete reference,herbet sheidt)chapter-13
PDF
Memory Management with Java and C++
PPT
What's New in C++ 11?
PPTX
Алексей Кутумов, Вектор с нуля
PPT
Memory Management In C++
PPTX
C++11: Feel the New Language
PPT
C++ Memory Management
PDF
C++20 the small things - Timur Doumler
KEY
Objective-Cひとめぐり
PDF
Memory Management C++ (Peeling operator new() and delete())
PDF
Writing Node.js Bindings - General Principles - Gabriel Schulhof
PDF
2 BytesC++ course_2014_c9_ pointers and dynamic arrays
PPTX
C# 6.0 Preview
TXT
Advance C++notes
PDF
The STL
PDF
Memory management in C++
C++11 & C++14
C++ 11 Features
C++ references
Lecture 3, c++(complete reference,herbet sheidt)chapter-13
Memory Management with Java and C++
What's New in C++ 11?
Алексей Кутумов, Вектор с нуля
Memory Management In C++
C++11: Feel the New Language
C++ Memory Management
C++20 the small things - Timur Doumler
Objective-Cひとめぐり
Memory Management C++ (Peeling operator new() and delete())
Writing Node.js Bindings - General Principles - Gabriel Schulhof
2 BytesC++ course_2014_c9_ pointers and dynamic arrays
C# 6.0 Preview
Advance C++notes
The STL
Memory management in C++
Ad

Viewers also liked (7)

DOCX
C++ & Design Patterns Quicky
PDF
C++11 smart pointers
PDF
Pointer in c++ part1
PPTX
Object Oriented Programming Using C++
PPT
Object-oriented concepts
PPT
Basic concepts of object oriented programming
PPTX
Oop c++class(final).ppt
C++ & Design Patterns Quicky
C++11 smart pointers
Pointer in c++ part1
Object Oriented Programming Using C++
Object-oriented concepts
Basic concepts of object oriented programming
Oop c++class(final).ppt
Ad

Similar to C++11 smart pointer (20)

PDF
smart pointers are unique concept to avoid memory leakage
PDF
C++11 talk
PPTX
Introduction to modern c++ principles(part 1)
PPTX
smart.pptxsmart.pptxsmart.pptxsmart.pptxsmart.pptx
PDF
Modern c++ Memory Management
PDF
std::shared_ptr<T> - (not so) Smart hammer for every pointy nail
PPTX
(Slightly) Smarter Smart Pointers
PPTX
Brian sabbeth smart_pointers
PPT
Gentle introduction to modern C++
PDF
Object Oriented Programming using C++ - Part 4
PPT
Beware of Pointers
PDF
C++ tutorial boost – 2013
PPT
Advance features of C++
PPT
Cppt 101102014428-phpapp01
PDF
An Overview Of Standard C++Tr1
PDF
C++ for Java Developers (JavaZone 2017)
PDF
Bjarne essencegn13
ODP
C++ Secure Programming
PPTX
C++ Chapter 11 OOP - Part 3
PPTX
Idiomatic C++
smart pointers are unique concept to avoid memory leakage
C++11 talk
Introduction to modern c++ principles(part 1)
smart.pptxsmart.pptxsmart.pptxsmart.pptxsmart.pptx
Modern c++ Memory Management
std::shared_ptr<T> - (not so) Smart hammer for every pointy nail
(Slightly) Smarter Smart Pointers
Brian sabbeth smart_pointers
Gentle introduction to modern C++
Object Oriented Programming using C++ - Part 4
Beware of Pointers
C++ tutorial boost – 2013
Advance features of C++
Cppt 101102014428-phpapp01
An Overview Of Standard C++Tr1
C++ for Java Developers (JavaZone 2017)
Bjarne essencegn13
C++ Secure Programming
C++ Chapter 11 OOP - Part 3
Idiomatic C++

C++11 smart pointer

  • 2. • Overview • shared_ptr • unique_ptr • weak_ptr – Cyclic reference problem – Enable shared from this • Miscs AGENDA
  • 3. • std::shared_ptr – shared ownership • std::unique_ptr – unique ownership • std::weak_ptr – No ownership • NO std::intrusive_ptr OVERVIEW • boost::shared_ptr – shared ownership • boost::scoped_ptr – unique ownership • boost::weak_ptr – No ownership ≈ Differences: • Compiler (C++11 vs C++03) • Move-Semantic • std::unique_ptr supports transfer-of-ownership • boost::scoped_ptr is neither copyable nor movable • Array support (See details in Miscs)
  • 5. • Features – share ownership – reference count – auto delete – native inheritance – cast • Overhead – Manager-Object* – Managed-Object-T* – Lock of increment/decrement of reference count (Thread safe) SHARED_PTR shared_ptr<T> Manager Object* T* Reference Counted with Lock Object T
  • 6. • Refer to objects allocated with new and can be deleted with delete • Create by new or make_shared – shared_ptr<T> t(new T(…)); – shared_ptr<T> t(make_shared<T>(…)); • Try hard to avoid using raw pointers – Mixing smart and built-in pointers can be hard to get right • Then never explicitly call delete RULES OF SHARED_PTR
  • 7. • shared_ptr<T> t(new T(…)); – Two dynamic allocations • shared_ptr<T> t(make_shared<T>(…)); – Single dynamic allocation • Why? – Manager-Object* – Managed-Object-T* • Prefer ::make_shared if a lof of shared_ptrs are created MAKE_SHARED VS NEW shared_ptr<T> Manager Object* T* Reference Counted with Lock Object T
  • 8. • http://ideone.com/aEFxlk BASIC USE OF SHARED_PTR std::shared_ptr<TClass> c2(new TClass(2)); // TClass 2 std::shared_ptr<TClass> c3 = std::make_shared<TClass>(3); std::shared_ptr<TClass> c4; // Empty shared_ptr c4.reset(new TClass(4)); // TClass: 4 if (c4) { ... // Do something } c4.reset(); // c4 becomes empty if (c4) { // Now it returns false ... // Code does not go here }
  • 9. • Same as raw pointer • http://ideone.com/jp4iCI INHERITANCE OF SHARED_PTR std::shared_ptr<TDerived> dp1(new TDerived); std::shared_ptr<TBase> bp1 = dp1; std::shared_ptr<TBase> bp2(dp1); std::shared_ptr<TBase> bp3(new TDerived);
  • 10. • Similar with raw pointer – static_pointer_cast – dynamic_pointer_cast – const_pointer_cast • Create a new shared_ptr! • http://ideone.com/TdcPDl CASTING SHARED_PTR std::shared_ptr<TBase> bp1(new TDerived); std::shared_ptr<const TBase> cbp(new TBase); std::shared_ptr<TDerived> dp1 = std::static_pointer_cast<TDerived>(bp1); std::shared_ptr<TDerived> dp2 = std::dynamic_pointer_cast<TDerived>(bp1); std::shared_ptr<TBase> bp2 = std::const_pointer_cast<TBase>(cbp); //std::shared_ptr<TDerived> d = static_cast<std::shared_ptr<TDerived>>(bp1); // Compile error
  • 12. • Features – Unique ownership • Copy constructor and copy assignment = delete – No reference count – auto delete – native inheritance – No cast, or manually cast • Overhead – Nothing! • Rules? – The same as shared_ptr UNIQUE_PTR
  • 13. • new or std::move (transfer ownership) • http://ideone.com/bxsFvC BASIC USE OF UNIQUE_PTR std::unique_ptr<TClass> c2(new TClass(2)); std::unique_ptr<TClass> c3; // Empty unique_ptr //c3 = c2; // error: use of deleted function operator=() c3 = std::move(c2); // unique_ptr has to be moved // Now c2 owns nothing // Note that return value of a function is a rvalue std::unique_ptr<TClass> GetATClass() { std::unique_ptr<TClass> c(new TClass(0)); return c; // same as `return std::move(c);` } c3 = GetATClass();
  • 14. • Same as raw pointer • http://ideone.com/FhgRi9 INHERITANCE OF UNIQUE_PTR std::unique_ptr<TDerived> dp1(new TDerived); std::unique_ptr<TBase> bp1 = std::move(dp1); std::unique_ptr<TBase> bp2(std::move(bp1)); std::unique_ptr<TBase> bp3(new TDerived);
  • 15. • Generally, do NOT cast • Why no native cast? – Cast makes a copy of the pointer • But I do want to cast unique_ptr? • http://ideone.com/F8CfIG CAST(MANUALLY) OF UNIQUE_PTR std::unique_ptr<TBase> bp1(new TDerived); std::unique_ptr<TDerived> dp1(static_cast<TDerived*>(bp1.get())); bp1.release(); // Now bp1 owns nothing bp1 = std::move(dp1); // Transfer ownership to bp1 (inheritance) std::unique_ptr<TDerived> dp2(dynamic_cast<TDerived*>(bp1.get())); bp1.release(); // Now bp1 owns nothing
  • 17. • “Observe” the managed object • Provide a shared_ptr when used • Why? – Solve cyclic reference of shared_ptr – Helps to get a shared_ptr from “this” WEAK_PTR
  • 18. • http://ideone.com/tZ3ZhJ BASIC USE OF WEAK_PTR std::weak_ptr<TClass> w; // Empty weak_ptr { std::shared_ptr<TClass> c(new TClass); // TClass: -1 std::weak_ptr<TClass> w1(c); // Construct from shared_ptr std::weak_ptr<TClass> w; // Empty weak_ptr w = c; std::weak_ptr<TClass> w3(w); w3.reset(); // w3 becomes empty w3 = w; // w3 points to the TClass as well std::shared_ptr<TClass> c2 = w.lock(); //Get shared_ptr by weak_ptr c2->IntValue = 1; } // ~TClass: 1 std::shared_ptr<TClass> c3 = w.lock(); // c3 is empty shared_ptr
  • 19. • http://ideone.com/KP8oSL CYCLIC REFERENCE PROBLEM class CyclicA { public: shared_ptr<CyclicB> b; }; class CyclicB { public: shared_ptr<CyclicA> a; }; void TestSharedPtrCyclicRef() { shared_ptr<CyclicA> a(new CyclicA); shared_ptr<CyclicB> b(new CyclicB); a->b = b; b->a = a; } // Neither a nor b is deleted
  • 20. • http://ideone.com/KP8oSL CYCLIC REFERENCE - FIX class FixCyclicA { public: std::shared_ptr<FixCyclicB> b; }; class FixCyclicB { public: std::weak_ptr<FixCyclicA> a; }; void TestWeakPtrFixCyclicRef() { std::shared_ptr<FixCyclicA> a(new FixCyclicA); std::shared_ptr<FixCyclicB> b(new FixCyclicB); a->b = b; b->a = a; } // Both a and b are deleted
  • 21. • How to get shared_ptr from class’s member function? ENABLE SHARED FROM THIS - WHY class TShareClass { ... std::shared_ptr<TShareClass> GetThis() { // how to achieve? } void CallFoo() { Foo(GetThis()); } } void Foo(const std::shared_ptr<TShareClass>& s) { // Do something to s, e.g. s->xxx = xxx }
  • 22. • A wrong way ENABLE SHARED FROM THIS – THE WRONG WAY class TShareClass { ... std::shared_ptr<TShareClass> GetThis () { return std::shared_ptr<TShareClass>(this); } // This gets deleted after out-of-scope } { std::shared_ptr<TShareClass> a(new TShareClass); std::shared_ptr<TShareClass> temp = a.GetThis(); } // Deleted twice!
  • 23. • One way to achieve: Add a weak_ptr ENABLE SHARED FROM THIS – AN ATTEMP class TMyShareClass { public: std::shared_ptr<TMyShareClass> GetThis() { return MyWeakPtr.lock(); // Make sure MyWeakPtr is valid } std::weak_ptr<TMyShareClass> MyWeakPtr; }; std::shared_ptr<TMyShareClass> c1(new TMyShareClass()); c1->MyWeakPtr = c1; std::shared_ptr<TMyShareClass> c2 = c1->GetThis();
  • 24. • C++11’s built-in enable_shared_from_this • http://ideone.com/wRUj3U ENABLE SHARED FROM THIS – A DECENT WAY class TShareClass : public std::enable_shared_from_this<TShareClass> { ... std::shared_ptr<TShareClass> GetThis() { return shared_from_this(); } }; std::shared_ptr<TShareClass> c1(new TShareClass()); std::shared_ptr<TShareClass> c2 = c1->GetThis();
  • 25. • Do not call shared_from_this()from constructor – weak_ptr is not valid yet in ctor • Always create shared_ptr<T>, never create raw T* • Consider make ctor/copy-ctors private and unique the creation – Prevent creating raw T in case of wrong usage – Benefit from perfect forwarding ENABLE SHARED FROM THIS – BE CAREFUL TShareClass* c1 = new TShareClass(); std::shared_ptr<TShareClass> c2 = c1->GetThis(); // Undefined behavior // Throws exception 'std::bad_weak_ptr‘ on gcc 4.9.x
  • 26. • Perfect creation of T (http://ideone.com/UyIPgb) class TPerfectCtor : public std::enable_shared_from_this<TPerfectCtor> { private: TPerfectCtor(int I = -1) = default; TPerfectCtor(const TPerfectCtor& r) = default; public: template<typename ... T> static std::shared_ptr<TPerfectCtor> Create(T&& ... all) { return std::shared_ptr<TPerfectCtor>( new TPerfectCtor(std::forward<T>(all)...)); } std::shared_ptr<TPerfectCtor> GetThis() { return shared_from_this(); } }; // std::shared_ptr<TPerfectCtor> c1(new TPerfectCtor()); // compile error std::shared_ptr<TPerfectCtor> c1 = TPerfectCtor::Create(); // TPerfectCtor: -1 std::shared_ptr<TPerfectCtor> c2 = TPerfectCtor::Create(2); // TPerfectCtor: 2 c2 = c1->GetThis(); // ~TPerfectCtor: 2 ENABLE SHARED FROM THIS – BEST PRACTICE
  • 27. Miscs
  • 28. • Default, use unique_ptr • Default, use unique_ptr in containers – std::vector<std::unique_ptr<T>> • If the object has shared ownership, use shared_ptr • If the objects have shared ownership, use shared_ptr in containers – std::vector<std::shared_ptr<T>> • Prefer to pass by const reference – void Foo(const std::shared_ptr<T>& sp); – void Foo(const std::unique_ptr<T>& up); Do not write like below – void Foo(std::shared_ptr<T>& sp); // Sometimes compile error – Why? sp.reset(new Base) while sp is Derived MISCS
  • 29. MISCS – ARRAY SUPPORT std::unique_ptr<T[]> ua(new T [5]); // OK boost::scoped_ptr<T[]> ua(new T [5]); // Compile error std::shared_ptr<T[]> ua(new T [5]); // Compile error boost::shared_ptr<T []> a(new T [5]); // OK (since Boost 1.53) // A custom deleter for array std::shared_ptr<T> a(new T [5], std::default_delete<T[]>()); // OK, but access with a.get()[index] // Never pass T[] to shared_ptr<T> std::shared_ptr<T> a(new T [5]); // Crash boost::shared_ptr<T> a(new T [5]); // Crash
  • 30. • Suggested ways to use array in smart pointer – std::unique_ptr<T[]> – std::shared_ptr<T> with custom delete – boost::shared_ptr<T[]> (Since Boost 1.53) – boost::shared_array<T> • Consider boost::ptr_vector<T> for vector of shared_ptr if performance is critical • http://ideone.com/n9lZJ2 MISCS – CONT.
  • 31. • boost’s Pointer Container Library – ptr_sequence_adapter • ptr_vector • ptr_list • ptr_deque • … – associative_ptr_container • ptr_set_adapter • ptr_multiset_adapter • ptr_map_adapter • … • boost::scoped_array • boost::intrusive_ptr FURTHER READINGS