The document discusses C++11 smart pointers including std::shared_ptr, std::unique_ptr, and std::weak_ptr. It provides an overview of their features and usage including shared ownership, unique ownership, no ownership. It demonstrates how to use them through examples and discusses best practices such as using std::make_shared to allocate objects, avoiding raw pointers, and enabling shared_from_this.
5. ? Features
¨C share ownership
¨C reference count
¨C auto delete
¨C native inheritance
¨C cast
? Overhead
¨C Manager-Object*
¨C Managed-Object-T*
¨C 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
¨C shared_ptr<T> t(new T(¡));
¨C shared_ptr<T> t(make_shared<T>(¡));
? Try hard to avoid using raw pointers
¨C 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(¡));
¨C Two dynamic allocations
? shared_ptr<T> t(make_shared<T>(¡));
¨C Single dynamic allocation
? Why?
¨C Manager-Object*
¨C 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
¨C static_pointer_cast
¨C dynamic_pointer_cast
¨C 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
¨C Unique ownership
? Copy constructor and copy assignment = delete
¨C No reference count
¨C auto delete
¨C native inheritance
¨C No cast, or manually cast
? Overhead
¨C Nothing!
? Rules?
¨C 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?
¨C 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?
¨C Solve cyclic reference of shared_ptr
¨C 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 ¨C 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 ¨C 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 ¨C 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
¨C 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
¨C Prevent creating raw T in case of wrong usage
¨C Benefit from perfect forwarding
ENABLE SHARED FROM THIS ¨C 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 ¨C BEST
PRACTICE
28. ? Default, use unique_ptr
? Default, use unique_ptr in containers
¨C 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
¨C std::vector<std::shared_ptr<T>>
? Prefer to pass by const reference
¨C void Foo(const std::shared_ptr<T>& sp);
¨C void Foo(const std::unique_ptr<T>& up);
Do not write like below
¨C void Foo(std::shared_ptr<T>& sp); // Sometimes compile error
¨C Why? sp.reset(new Base) while sp is Derived
MISCS
29. MISCS ¨C 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
¨C std::unique_ptr<T[]>
¨C std::shared_ptr<T> with custom delete
¨C boost::shared_ptr<T[]> (Since Boost 1.53)
¨C boost::shared_array<T>
? Consider boost::ptr_vector<T> for vector of shared_ptr if
performance is critical
? http://ideone.com/n9lZJ2
MISCS ¨C CONT.