SlideShare a Scribd company logo
2
Most read
3
Most read
5
Most read
Smart Pointers in C++
Francesco Casalegno
Raw pointers are dangerous!
● In C++ we use pointers to handle memory that was dynamically allocated with new.
However, raw pointers can be dangerous for many reasons.
2
Person* p = new Person("John", 25);
p->call(); // exception may be thrown here...
delete p; // ... and we never get here!
→ Missing delete causes memory leaks.
This easily happens when exceptions are not correctly handled.
→ Calling delete more than once yields undefined behavior.
Person* p = new Person("John", 25);
Person* q = p;
delete p;
delete q; // undefined behavior: object already deleted!
→ After a delete we get a dangling pointer.
Person* p = new Person[10];
delete[] p; // p still points to the same memory location!
p[0]->call(); // undefined behavior!
p = nullptr; // ok, now p is not dangling any more
Smart Pointers
● You can avoid these drawbacks by using smart pointers.
A smart pointers is a wrapper of a raw pointer providing same functionalities with more safety:
→ same syntax as raw pointers for deferencing: *p, p->val, and p[idx]
→ automatic management of dynamically allocated memory lifetime
→ exception-safe destruction
→ automatically set to nullptr, avoiding dangling pointers
● We have 4 kinds of smart pointers, all defined in the header <memory>
→ std::auto_ptr (from C++98) was a first naive attempt to implement a smart pointer with
exclusive-ownership. It is deprecated from C++11, and removed from the STL from C++14.
→ std::unique_ptr (from C++11) is a smart pointer used for exclusive-ownership
that can be copied only with move semantics.
→ std::shared_ptr (from C++11) is a smart pointer used for shared-ownership with automatic
garbage collection based on a reference count.
→ std::weak_ptr (from C++11) is a smart pointer used for observing without owning. It is similar to
std::shared_ptr, but it does not contribute to the reference count. 3
std::auto_ptr
● An auto_ptr provides exclusive ownership for a pointer that it holds. When auto_ptr is destroyed, the
object pointed is also automatically destroyed through a call to delete.
● Introduced pre C++11, so no move semantics: how to copy the pointer while keeping exclusivity?
Workaround: c-tor and assignment receive by value and steal the ownership!
● This (deprecated) smart pointers clearly had many issues:
→ when it gets destroyed it always call delete, so no dynamic arrays (delete[])
→ copy / move c-tor and assignment take arguments by non-const argument (same behavior for
lval or rval) and have strange side-effects (stealing ownership): does not respect the natural
requirements of CopyConstructible and CopyAssignable
→ therefore it cannot be used in STL containers (pre C++11) or it is deprecated to do it (C++11)
... If you have C++11, then just use std::unique_ptr instead!
4
{
std::auto_ptr<Person> p(new Person("John", 25));
p->call(); // if exception is thrown, delete is automatically called
} // here p goes out of scope, delete is automatically called
std::auto_ptr<Person> p("John", 25);
std::auto_ptr<Person> q = p; // copy c-tor: q points to object, p is nullptr!
p = q; // copy assignment: p points to object, q is nullptr!
std::unique_ptr
● A unique_prt u provides exclusive ownership for the pointer p that it holds. When u is destroyed, the
object pointed by p is disposed using p’s associated deleter (custom of default delete/delete[] )
● Main difference with respect to auto_prt:
→ copy c-tor and assignment are deleted, so that copying from lvalue is not allowed
→ move c-tor and assignment are implemented to allow ownership change by natural move semantics
5
std::unique_ptr<Person> p(new Person("John", 25));
std::unique_ptr<Person> q = p; // compiler error! copy c-tor is deleted
std::unique_ptr<Person> q = std::move(p); // ok, move c-tor called
p = q; // compiler error! copy assignment is deleted
p = std::move(q); // ok, move assignment called
● Important features:
→ template specialization unique_prt<T[]> to handle dynamic arrays
→ copy from lvalue is deleted, copy from rvalue is implemented using move semantics
so that it can suitably work in a STL container
→ custom deleter can be provided if needed
→ pretty simple wrapper implementation, so no overhead in memory (unless custom deleter) or runtime
→ easy conversion to shared_ptr
John
Alice
std::unique_ptr – useful methods
● Observes
● Modifiers
6
pointer get() const;
→ returns a pointer to the managed object
deleter& get_deleter();
→ returns a reference to the deleter object used for the disposal of the managed object
pointer release();
→ releases ownership by returning the managed object + setting the internal pointer to nullptr
void reset( pointer ptr = pointer() );
→ replaces the internal pointer with ptr, and disposes of the previously owned object by calling
the deleter
std::shared_ptr
● A shared_ptr provides shared ownership: many pointers may own the same object and the last one
to survive is responsible of its disposal through the deleter.
● This garbage collection mechanism is based on a reference counter contained in a control block.
Each new shared owner copies the pointer to the control block and increases the count by 1.
● Important features:
→ until C++17 no template specialization shared_prt<T[]> to handle dynamic arrays
→ custom deleter and custom allocator (for internal data allocation) can be provided if needed
→ it is CopyConstructible and CopyAssignable, so it can work in a STL container
→ non-trivial implementation and memory overhead (typically 2 pointers: object itself + ctrl block)
→ many operations require atomic (thread safety!) update of ref_counter, which may be slow
→ aliasing c-tor allows to share ownership on an object and point elsewhere (e.g. object’s member)
7
std::shared_ptr p(new Person("John", 25)); // construction: ref_counter=1
std::shared_ptr q = p; // new owner: ref_counter=2
std::shared_ptr r = std::move(p); // r steals ownership: ref_counter=2
p.reset(new Person("Alice", 23)); // p resets managed object: ref_counter=1
r = nullptr; // move assign to nullptr: ref_counter=0,
and deleter is called!
ptr to obj
shared_ptr
“John”
25
ref_counter
custom del
custom alloc
ptr to ctrl
John
object controller
std::shared_ptr – useful methods
● Observes
● Modifiers
8
T* get() const;
→ returns stored pointer
long use_count() const;
→ returns the number of shared pointers managing current object
bool unique() const noexcept;
→ returns whether use_count()==1
template< class Y > void reset( Y* ptr );
→ replaces the managed object with the one pointed by ptr, and disposes of the previously
owned object by calling the deleter
std::weak_ptr
● A weak_ptr tracks without owning a pointer to an object managed by a shared_ptr. It implements weak
ownership: the object needs to be accessed only if still exists, and it may be deleted by others.
If we need to access the object we have to convert it into a shared_ptr.
● Used as observer to determine if the pointer is dangling before converting to shared_ptr and using it.
Typical use cases are implementing a cache and breaking cycles:
Example with cycles: how to do if A and C share ownership on B, but B must also point to A?
→ raw ptr: if A gets destroyed, B has no way to know it and its pointer dangles
→ shared_ptr: if C gets destroyed we still have a cycle and therefore A and B are never deleted!
The only reasonable solution is weak_ptr!
● Important features:
→ cannot directly access the pointed object: *p, p->val, or p[idx] are not implemented!
→ convert to shared_ptr (after check for dangling!) when you need to access object
→ implemented very similar to shared_ptr, but no contribution to ref_counter update
→ same memory overhead as shared_ptr, and performance penalty for accessing due to
conversion
9
A B C
John Alice
std::weak_ptr – useful methods
● Observes
● Modifiers
10
long use_count() const;
→ returns the number of shared pointers managing current object
bool expired() const;
→ check if use_count()==0
std::shared_ptr<T> lock() const;
→ creates a new shared_ptr owning the managed object
template< class Y > void reset();
→ releases the reference to the managed object
Avoid new, use factories
● Using std::unique_ptr and std::shared_ptr avoid memory leaks through automatic life-time
management and garbage collection. Basically, we do not need to call delete any more!
● However, we still need to call new operator when we call the constructor. This is bad for 2 reasons.
→ Since function arguments can be evaluated in any order, if throw() occurs we may have a leak
→ For shared_ptr, calling the c-tor with new inside causes a double allocation (one for the
object itself, one for the control block) and therefore time penalty
● C++ provides us with factories that fix this issue:
→ std::make_unique (from C++14, but implementation is trivial)
→ std::make_shared (from C++11)
→ std::allocate_shared (from C++11, same as make_shared but with custom memory allocator)
● There is a caveat with make_shared. As the allocation is made for object + ctrl block together, as long
as a weak_ptr needs the ctrl block to be alive, the object cannot be destroyed!
11
foo(std::unique_ptr<double[]>(new double[10]), bar(42));
// argument evaluation could be: i) new double[10], ii) bar(42) iii) unique_ptr c-tor
// if at ii) bar(42) throws, no one will call delete[] on the memory allocated during i) !!
Do we still need raw pointers?
● Smart pointers implement automatic management of dynamically allocated memory.
This comes with little overhead, or even no overhead as in the case of unique_ptr.
● However, there are still cases when raw pointers are needed.
→ when the pointer really just mean an address, not ownership of an object
→ to implement iterators
→ to handle an array decaying into a pointer
→ when working with legacy code (e.g. pre-C++11)
→ when passing arguments by address to modify their content
12
Take-Home Message
1. Raw ptrs are dangerous when handling dynamically allocated memory.
Smart ptrs are a safe alternative, with little or no overhead, providing automatic management of owned objects.
2. Use std::unique_ptr to implement exclusive ownership and transfer it using std::move.
3. Use std::shared_ptr to implement shared ownership: the garbage collector mechanism (based on a ref_counter in the
control block) deletes the object when no more share pointers owns it. Be aware of the overhead of this choice.
4. Use std::weak_ptr to observe without owning an object managed by a shared_ptr, and in particular to solve reference
cycles. Accessing the object is possible through a conversion to shared_ptr, which causes some overhead.
5. In general it is a good idea to use make_shared and make_unique whenever possible in order to avoid memory leaks
and provide exception safety, as well as to avoid double memory allocation for shared_ptr.
13
Main References:
→ Meyers, Scott. Effective modern C++: 42 specific ways to improve your use of C++ 11 and C++ 14. " O'Reilly Media, Inc.", 2014.
→ ISO C++ Standards ISO/IEC 14882:2011 and ISO/IEC 14882:2014

More Related Content

PPTX
Object Oriented Programming using C++(UNIT 1)
PPTX
Programming Language Evolution
PPTX
Romero Blueprint Compendium
PPTX
Pointers in c++
PPTX
Artifical Intelligence
PPTX
Evolution of Programming language
PPTX
Presentation on C++ Programming Language
PPTX
Templates in c++
Object Oriented Programming using C++(UNIT 1)
Programming Language Evolution
Romero Blueprint Compendium
Pointers in c++
Artifical Intelligence
Evolution of Programming language
Presentation on C++ Programming Language
Templates in c++

What's hot (20)

PPTX
Smart pointers
PDF
Function in C
PPTX
C programming - String
PPTX
Inline function
PPTX
Function in c program
PPTX
Inheritance in c++
PPTX
Pointers and Structures.pptx
PPTX
CONDITIONAL STATEMENT IN C LANGUAGE
PPSX
Break and continue
PPTX
Templates in C++
PPT
structure and union
PPTX
Functions in c
PPTX
Call by value or call by reference in C++
PPTX
Constructor in java
PPT
C++: Constructor, Copy Constructor and Assignment operator
PPT
Advanced pointers
PPTX
Pointer arithmetic in c
PPTX
C programming - Pointers
PPT
pre processor directives in C
Smart pointers
Function in C
C programming - String
Inline function
Function in c program
Inheritance in c++
Pointers and Structures.pptx
CONDITIONAL STATEMENT IN C LANGUAGE
Break and continue
Templates in C++
structure and union
Functions in c
Call by value or call by reference in C++
Constructor in java
C++: Constructor, Copy Constructor and Assignment operator
Advanced pointers
Pointer arithmetic in c
C programming - Pointers
pre processor directives in C
Ad

Similar to Smart Pointers in C++ (20)

PDF
smart pointers are unique concept to avoid memory leakage
PDF
(3) cpp abstractions more_on_user_defined_types
PDF
(4) cpp abstractions references_copies_and_const-ness
PDF
Cpp17 and Beyond
PDF
C++11 smart pointer
PDF
Where destructors meet threads
PDF
One Careful Owner
PDF
CS225_Prelecture_Notes 2nd
PDF
Take advantage of C++ from Python
PPTX
C++11: Feel the New Language
PDF
L6
PPT
Handling Exceptions In C &amp; C++ [Part B] Ver 2
PPTX
Object orinted programming lecture| Variables
PDF
C++11: Rvalue References, Move Semantics, Perfect Forwarding
PDF
(5) cpp dynamic memory_arrays_and_c-strings
PDF
C++_notes.pdf
PDF
(5) cpp abstractions essential_operators
PPTX
smart.pptxsmart.pptxsmart.pptxsmart.pptxsmart.pptx
PPTX
smart.pptxsmart.pptxsmart.pptxsmart.pptxsmart.pptx
TXT
Advance C++notes
smart pointers are unique concept to avoid memory leakage
(3) cpp abstractions more_on_user_defined_types
(4) cpp abstractions references_copies_and_const-ness
Cpp17 and Beyond
C++11 smart pointer
Where destructors meet threads
One Careful Owner
CS225_Prelecture_Notes 2nd
Take advantage of C++ from Python
C++11: Feel the New Language
L6
Handling Exceptions In C &amp; C++ [Part B] Ver 2
Object orinted programming lecture| Variables
C++11: Rvalue References, Move Semantics, Perfect Forwarding
(5) cpp dynamic memory_arrays_and_c-strings
C++_notes.pdf
(5) cpp abstractions essential_operators
smart.pptxsmart.pptxsmart.pptxsmart.pptxsmart.pptx
smart.pptxsmart.pptxsmart.pptxsmart.pptxsmart.pptx
Advance C++notes
Ad

More from Francesco Casalegno (7)

PDF
DVC - Git-like Data Version Control for Machine Learning projects
PDF
Ordinal Regression and Machine Learning: Applications, Methods, Metrics
PDF
Recommender Systems
PDF
Markov Chain Monte Carlo Methods
PDF
Hyperparameter Optimization for Machine Learning
PDF
Confidence Intervals––Exact Intervals, Jackknife, and Bootstrap
PDF
[C++] The Curiously Recurring Template Pattern: Static Polymorphsim and Expre...
DVC - Git-like Data Version Control for Machine Learning projects
Ordinal Regression and Machine Learning: Applications, Methods, Metrics
Recommender Systems
Markov Chain Monte Carlo Methods
Hyperparameter Optimization for Machine Learning
Confidence Intervals––Exact Intervals, Jackknife, and Bootstrap
[C++] The Curiously Recurring Template Pattern: Static Polymorphsim and Expre...

Recently uploaded (20)

PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PPTX
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
PPTX
Programs and apps: productivity, graphics, security and other tools
PPTX
Spectroscopy.pptx food analysis technology
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PPTX
Big Data Technologies - Introduction.pptx
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PPTX
sap open course for s4hana steps from ECC to s4
PDF
Electronic commerce courselecture one. Pdf
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PPT
Teaching material agriculture food technology
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
Programs and apps: productivity, graphics, security and other tools
Spectroscopy.pptx food analysis technology
“AI and Expert System Decision Support & Business Intelligence Systems”
Digital-Transformation-Roadmap-for-Companies.pptx
Big Data Technologies - Introduction.pptx
Diabetes mellitus diagnosis method based random forest with bat algorithm
Network Security Unit 5.pdf for BCA BBA.
Reach Out and Touch Someone: Haptics and Empathic Computing
sap open course for s4hana steps from ECC to s4
Electronic commerce courselecture one. Pdf
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
Advanced methodologies resolving dimensionality complications for autism neur...
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
Building Integrated photovoltaic BIPV_UPV.pdf
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
Teaching material agriculture food technology
Per capita expenditure prediction using model stacking based on satellite ima...

Smart Pointers in C++

  • 1. Smart Pointers in C++ Francesco Casalegno
  • 2. Raw pointers are dangerous! ● In C++ we use pointers to handle memory that was dynamically allocated with new. However, raw pointers can be dangerous for many reasons. 2 Person* p = new Person("John", 25); p->call(); // exception may be thrown here... delete p; // ... and we never get here! → Missing delete causes memory leaks. This easily happens when exceptions are not correctly handled. → Calling delete more than once yields undefined behavior. Person* p = new Person("John", 25); Person* q = p; delete p; delete q; // undefined behavior: object already deleted! → After a delete we get a dangling pointer. Person* p = new Person[10]; delete[] p; // p still points to the same memory location! p[0]->call(); // undefined behavior! p = nullptr; // ok, now p is not dangling any more
  • 3. Smart Pointers ● You can avoid these drawbacks by using smart pointers. A smart pointers is a wrapper of a raw pointer providing same functionalities with more safety: → same syntax as raw pointers for deferencing: *p, p->val, and p[idx] → automatic management of dynamically allocated memory lifetime → exception-safe destruction → automatically set to nullptr, avoiding dangling pointers ● We have 4 kinds of smart pointers, all defined in the header <memory> → std::auto_ptr (from C++98) was a first naive attempt to implement a smart pointer with exclusive-ownership. It is deprecated from C++11, and removed from the STL from C++14. → std::unique_ptr (from C++11) is a smart pointer used for exclusive-ownership that can be copied only with move semantics. → std::shared_ptr (from C++11) is a smart pointer used for shared-ownership with automatic garbage collection based on a reference count. → std::weak_ptr (from C++11) is a smart pointer used for observing without owning. It is similar to std::shared_ptr, but it does not contribute to the reference count. 3
  • 4. std::auto_ptr ● An auto_ptr provides exclusive ownership for a pointer that it holds. When auto_ptr is destroyed, the object pointed is also automatically destroyed through a call to delete. ● Introduced pre C++11, so no move semantics: how to copy the pointer while keeping exclusivity? Workaround: c-tor and assignment receive by value and steal the ownership! ● This (deprecated) smart pointers clearly had many issues: → when it gets destroyed it always call delete, so no dynamic arrays (delete[]) → copy / move c-tor and assignment take arguments by non-const argument (same behavior for lval or rval) and have strange side-effects (stealing ownership): does not respect the natural requirements of CopyConstructible and CopyAssignable → therefore it cannot be used in STL containers (pre C++11) or it is deprecated to do it (C++11) ... If you have C++11, then just use std::unique_ptr instead! 4 { std::auto_ptr<Person> p(new Person("John", 25)); p->call(); // if exception is thrown, delete is automatically called } // here p goes out of scope, delete is automatically called std::auto_ptr<Person> p("John", 25); std::auto_ptr<Person> q = p; // copy c-tor: q points to object, p is nullptr! p = q; // copy assignment: p points to object, q is nullptr!
  • 5. std::unique_ptr ● A unique_prt u provides exclusive ownership for the pointer p that it holds. When u is destroyed, the object pointed by p is disposed using p’s associated deleter (custom of default delete/delete[] ) ● Main difference with respect to auto_prt: → copy c-tor and assignment are deleted, so that copying from lvalue is not allowed → move c-tor and assignment are implemented to allow ownership change by natural move semantics 5 std::unique_ptr<Person> p(new Person("John", 25)); std::unique_ptr<Person> q = p; // compiler error! copy c-tor is deleted std::unique_ptr<Person> q = std::move(p); // ok, move c-tor called p = q; // compiler error! copy assignment is deleted p = std::move(q); // ok, move assignment called ● Important features: → template specialization unique_prt<T[]> to handle dynamic arrays → copy from lvalue is deleted, copy from rvalue is implemented using move semantics so that it can suitably work in a STL container → custom deleter can be provided if needed → pretty simple wrapper implementation, so no overhead in memory (unless custom deleter) or runtime → easy conversion to shared_ptr John Alice
  • 6. std::unique_ptr – useful methods ● Observes ● Modifiers 6 pointer get() const; → returns a pointer to the managed object deleter& get_deleter(); → returns a reference to the deleter object used for the disposal of the managed object pointer release(); → releases ownership by returning the managed object + setting the internal pointer to nullptr void reset( pointer ptr = pointer() ); → replaces the internal pointer with ptr, and disposes of the previously owned object by calling the deleter
  • 7. std::shared_ptr ● A shared_ptr provides shared ownership: many pointers may own the same object and the last one to survive is responsible of its disposal through the deleter. ● This garbage collection mechanism is based on a reference counter contained in a control block. Each new shared owner copies the pointer to the control block and increases the count by 1. ● Important features: → until C++17 no template specialization shared_prt<T[]> to handle dynamic arrays → custom deleter and custom allocator (for internal data allocation) can be provided if needed → it is CopyConstructible and CopyAssignable, so it can work in a STL container → non-trivial implementation and memory overhead (typically 2 pointers: object itself + ctrl block) → many operations require atomic (thread safety!) update of ref_counter, which may be slow → aliasing c-tor allows to share ownership on an object and point elsewhere (e.g. object’s member) 7 std::shared_ptr p(new Person("John", 25)); // construction: ref_counter=1 std::shared_ptr q = p; // new owner: ref_counter=2 std::shared_ptr r = std::move(p); // r steals ownership: ref_counter=2 p.reset(new Person("Alice", 23)); // p resets managed object: ref_counter=1 r = nullptr; // move assign to nullptr: ref_counter=0, and deleter is called! ptr to obj shared_ptr “John” 25 ref_counter custom del custom alloc ptr to ctrl John object controller
  • 8. std::shared_ptr – useful methods ● Observes ● Modifiers 8 T* get() const; → returns stored pointer long use_count() const; → returns the number of shared pointers managing current object bool unique() const noexcept; → returns whether use_count()==1 template< class Y > void reset( Y* ptr ); → replaces the managed object with the one pointed by ptr, and disposes of the previously owned object by calling the deleter
  • 9. std::weak_ptr ● A weak_ptr tracks without owning a pointer to an object managed by a shared_ptr. It implements weak ownership: the object needs to be accessed only if still exists, and it may be deleted by others. If we need to access the object we have to convert it into a shared_ptr. ● Used as observer to determine if the pointer is dangling before converting to shared_ptr and using it. Typical use cases are implementing a cache and breaking cycles: Example with cycles: how to do if A and C share ownership on B, but B must also point to A? → raw ptr: if A gets destroyed, B has no way to know it and its pointer dangles → shared_ptr: if C gets destroyed we still have a cycle and therefore A and B are never deleted! The only reasonable solution is weak_ptr! ● Important features: → cannot directly access the pointed object: *p, p->val, or p[idx] are not implemented! → convert to shared_ptr (after check for dangling!) when you need to access object → implemented very similar to shared_ptr, but no contribution to ref_counter update → same memory overhead as shared_ptr, and performance penalty for accessing due to conversion 9 A B C John Alice
  • 10. std::weak_ptr – useful methods ● Observes ● Modifiers 10 long use_count() const; → returns the number of shared pointers managing current object bool expired() const; → check if use_count()==0 std::shared_ptr<T> lock() const; → creates a new shared_ptr owning the managed object template< class Y > void reset(); → releases the reference to the managed object
  • 11. Avoid new, use factories ● Using std::unique_ptr and std::shared_ptr avoid memory leaks through automatic life-time management and garbage collection. Basically, we do not need to call delete any more! ● However, we still need to call new operator when we call the constructor. This is bad for 2 reasons. → Since function arguments can be evaluated in any order, if throw() occurs we may have a leak → For shared_ptr, calling the c-tor with new inside causes a double allocation (one for the object itself, one for the control block) and therefore time penalty ● C++ provides us with factories that fix this issue: → std::make_unique (from C++14, but implementation is trivial) → std::make_shared (from C++11) → std::allocate_shared (from C++11, same as make_shared but with custom memory allocator) ● There is a caveat with make_shared. As the allocation is made for object + ctrl block together, as long as a weak_ptr needs the ctrl block to be alive, the object cannot be destroyed! 11 foo(std::unique_ptr<double[]>(new double[10]), bar(42)); // argument evaluation could be: i) new double[10], ii) bar(42) iii) unique_ptr c-tor // if at ii) bar(42) throws, no one will call delete[] on the memory allocated during i) !!
  • 12. Do we still need raw pointers? ● Smart pointers implement automatic management of dynamically allocated memory. This comes with little overhead, or even no overhead as in the case of unique_ptr. ● However, there are still cases when raw pointers are needed. → when the pointer really just mean an address, not ownership of an object → to implement iterators → to handle an array decaying into a pointer → when working with legacy code (e.g. pre-C++11) → when passing arguments by address to modify their content 12
  • 13. Take-Home Message 1. Raw ptrs are dangerous when handling dynamically allocated memory. Smart ptrs are a safe alternative, with little or no overhead, providing automatic management of owned objects. 2. Use std::unique_ptr to implement exclusive ownership and transfer it using std::move. 3. Use std::shared_ptr to implement shared ownership: the garbage collector mechanism (based on a ref_counter in the control block) deletes the object when no more share pointers owns it. Be aware of the overhead of this choice. 4. Use std::weak_ptr to observe without owning an object managed by a shared_ptr, and in particular to solve reference cycles. Accessing the object is possible through a conversion to shared_ptr, which causes some overhead. 5. In general it is a good idea to use make_shared and make_unique whenever possible in order to avoid memory leaks and provide exception safety, as well as to avoid double memory allocation for shared_ptr. 13 Main References: → Meyers, Scott. Effective modern C++: 42 specific ways to improve your use of C++ 11 and C++ 14. " O'Reilly Media, Inc.", 2014. → ISO C++ Standards ISO/IEC 14882:2011 and ISO/IEC 14882:2014