SMART POINTERS in C++ (std::unique_ptr, std::shared_ptr, std::weak_ptr)
Summary
TLDRThis video script delves into the concept of smart pointers in C++, a feature designed to automate memory management. It explains that smart pointers, such as unique and shared pointers, act as wrappers around raw pointers to handle memory allocation and deallocation automatically. Unique pointers prevent copying to avoid multiple owners of the same memory, ensuring automatic deletion when out of scope. Shared pointers, on the other hand, use reference counting to manage multiple references safely. The script also touches on weak pointers for non-owning references. The presenter suggests that while smart pointers are beneficial for preventing memory leaks, they don't entirely replace the need for manual memory management with 'new' and 'delete', recommending the use of unique pointers by default due to their lower overhead.
Takeaways
- 📌 Smart pointers in C++ are designed to automate memory management, eliminating the need for manual calls to `new` and `delete`.
- 🔑 A smart pointer acts as a wrapper around a raw pointer, managing the allocation and deallocation of memory on the heap.
- 👤 Unique pointers (`std::unique_ptr`) are non-copyable and are used for exclusive ownership of a resource, automatically deleting the object when the pointer goes out of scope.
- 🔄 The copy constructor and assignment operator for unique pointers are deleted to prevent multiple owners of the same resource, which could lead to double deletion and undefined behavior.
- 🚫 `std::make_unique` is the preferred way to create unique pointers due to its exception safety; it avoids potential memory leaks if an exception occurs during object construction.
- 🤝 Shared pointers (`std::shared_ptr`) allow for shared ownership of a resource through reference counting, where the resource is only deleted when the last shared pointer goes out of scope.
- 📈 Reference counting in shared pointers involves allocating an additional control block to keep track of the number of references, which adds some overhead compared to unique pointers.
- 🔄 `std::make_shared` is the recommended method for creating shared pointers as it is more efficient and exception-safe compared to using `new` followed by the shared pointer constructor.
- 🔗 Weak pointers (`std::weak_ptr`) provide a non-owning reference to an object managed by shared pointers, useful for breaking reference cycles and can be used to check if the object is still valid.
- ♻️ Smart pointers help prevent memory leaks and simplify memory management, but they are not a complete replacement for `new` and `delete`, especially in cases where explicit control over memory allocation is necessary.
- 🛠️ The choice between unique and shared pointers depends on the use case, with unique pointers being the first preference due to lower overhead, followed by shared pointers when sharing is necessary.
Q & A
What are smart pointers in C++?
-Smart pointers in C++ are a feature that automates memory management. They wrap around a raw pointer, managing the allocation and deallocation of memory on the heap, so you don't have to manually call 'new' and 'delete'.
Why should one consider using smart pointers?
-Smart pointers should be considered for their ability to automate memory management, preventing memory leaks by ensuring that memory is properly freed when it's no longer needed, without the programmer having to explicitly call 'delete'.
What is the difference between a unique pointer and a shared pointer in C++?
-A unique pointer is a smart pointer that owns the object it points to and ensures that there is only one owner of the object. It cannot be copied. A shared pointer, on the other hand, maintains a reference count to keep track of how many pointers share ownership of the same object, and it can be copied.
Why are unique pointers called 'unique'?
-Unique pointers are called 'unique' because they must be the sole owner of the object they point to. Copying a unique pointer is not allowed to prevent multiple owners from causing issues when the memory is freed.
What is the preferred way to create a unique pointer in C++?
-The preferred way to create a unique pointer is by using 'std::make_unique', which is safer in terms of exception handling because it prevents the creation of a dangling pointer in case of an exception during object construction.
How does the reference counting mechanism work with shared pointers?
-Reference counting with shared pointers works by keeping track of how many shared pointers are pointing to a particular object. When the reference count reaches zero, indicating no shared pointers are referencing the object, the object is deleted and its memory is freed.
What is a weak pointer and what is its purpose?
-A weak pointer is a smart pointer that does not increase the reference count when it holds a reference to an object. It is used to break reference cycles and to hold a non-owning reference to an object that is managed by shared pointers.
What is the overhead associated with using shared pointers?
-The overhead associated with shared pointers comes from the additional memory required for the reference count and the control block, as well as the potential performance cost of incrementing and decrementing the reference count.
Why should one avoid using 'new' with shared pointers?
-Using 'new' with shared pointers is not recommended because it requires an additional allocation for the control block, which can be avoided by using 'std::make_shared', making the process more efficient and exception-safe.
What is the general recommendation for when to use unique pointers versus shared pointers?
-Unique pointers should be used as the first preference when you need a single owner for the object. Shared pointers should be used when you need to share ownership of an object between multiple pointers, but be aware of the additional overhead they introduce.
Outlines
🔒 Introduction to Smart Pointers in C++
The video script introduces the concept of smart pointers in C++, explaining their purpose and functionality. The narrator discusses how smart pointers automate memory management by eliminating the need for explicit calls to 'new' and 'delete'. The script introduces 'unique pointers' as a type of smart pointer that cannot be copied, ensuring that there is only one owner of the memory block it points to. This is crucial for preventing memory leaks and ensuring safe programming practices. The video also touches on the idea of stack allocation and object lifetimes, suggesting that viewers refer to a previous video for more details on these topics.
🔄 Understanding Unique and Shared Pointers
This paragraph delves deeper into the workings of unique pointers, emphasizing their role in stack allocation and their inability to be copied due to the risk of double deletion. The script then contrasts unique pointers with shared pointers, which utilize reference counting to manage memory. Shared pointers allow multiple pointers to reference the same memory block, safely incrementing and decrementing a reference count to determine when the memory can be freed. The video script provides a practical example of using shared pointers, demonstrating how they can be copied and how the reference count affects their behavior. Additionally, the script introduces weak pointers as a way to hold a non-owning reference to an object pointed to by a shared pointer.
🛠️ Practical Usage and Recommendations for Smart Pointers
The final paragraph discusses the practical usage of smart pointers in C++ programming. The narrator suggests that smart pointers should be used whenever possible due to their ability to automate memory management and prevent memory leaks. The script provides guidance on when to use unique pointers versus shared pointers, recommending unique pointers for their lower overhead and shared pointers for cases where memory needs to be shared. The narrator also acknowledges that while smart pointers are powerful, they have not completely replaced the need for 'new' and 'delete' in certain scenarios. The video concludes with a call to action for viewers to engage with the content through likes, comments, and support on Patreon.
Mindmap
Keywords
💡Smart Pointers
💡Unique Pointers
💡Stack Allocation
💡Reference Counting
💡Shared Pointers
💡Memory Management
💡Exception Safety
💡Control Block
💡Weak Pointers
💡Ownership
Highlights
Introduction to smart pointers in C++ and their automation of memory management.
Explanation of how smart pointers eliminate the need for manual calls to 'new' and 'delete'.
Overview of unique pointers and their single ownership semantics.
Unique pointers' inability to be copied to prevent double deletion of the same memory block.
Demonstration of creating a unique pointer and its automatic destruction when out of scope.
Introduction to 'std::make_unique' for safer exception handling when creating unique pointers.
Difference between unique pointers and shared pointers regarding object lifetime management.
Description of shared pointers and their use of reference counting for memory management.
Shared pointers' ability to be copied and their impact on reference count.
Advantages of using 'std::make_shared' for efficiency and exception safety.
Explanation of weak pointers and their role in not increasing the reference count.
Use cases for weak pointers when you do not want to take ownership of the object.
Discussion on when to use smart pointers and the preference for 'unique_ptr' over 'shared_ptr'.
The presenter's perspective on smart pointers not completely replacing 'new' and 'delete'.
Recommendation to use unique pointers for lower overhead when appropriate.
Encouragement to use smart pointers to automate memory management and prevent leaks.
Invitation for viewers to join the presenter's Discord server for further questions and discussions.
Call to action for supporting the series on Patreon for additional content and rewards.
Transcripts
hey what's up guys my name is a channel
welcome back to my state boss last
series today we're gonna be talking all
about smart pointers in C++
so as my pointers are a topic that has
come up a lot recently in my videos and
people requesting this and what is a
smart pointer should I be using smart
pointers and all that today we just goes
over what they are we're not really
going to get into depth about what why I
think you should or shouldn't be using
them and all that stuff and my opinions
about smart pointers in general I'm
gonna save that for another video today
we're just gonna focus on what a smart
pointer is and what it can do for you so
earlier we talked about what new and
delete does new allocates memory on the
heap and delete is needed to delete that
memory to free that memory because it
won't be freed automatically smart
pointers are a way to automate that
process that's all they are right smart
pointers mean that when you call new you
don't have to call delete and in fact in
many cases with smart pointers we don't
even have to call new so a lot of people
tend to have this kind of programming
style and safe as possible they never
ever call new or delete and smart
pointers are best their way to make that
happen so smart pointers are essentially
a wrapper around a real raw pointer when
you create a smart pointer and you make
it it will call new and allocate your
memory for you and then based on which
my pointer you use that memory will at
some point be automatically free so
let's take a look at the first kind of
an simplest smart border that we have
unique pointers so a unique pointer is a
script pointer meaning that when that
pointer goes out of scope it will it
will get destroyed and it will call
delete we actually talked about how
object lifetimes work and how you can
leverage the power of stack allocation
all that in the last video so definitely
check that out if you haven't already
but that is basically our script points
work or unique pointers there isn't
they're called unique pointers it
because they have to be unique you can't
copy a unique pointer because if you
copy a unique pointer the memory that
it's pointing to they'll basically
you'll have two pointers two unique
pointers pointing to the same block of
memory and when one of them dies it will
free that memory meaning that suddenly
that second unique pointer you had
pointed to the same book of memory is
pointing to memory that's been freed so
you cannot copy unique pointers you need
pointers are for when you want a skrub
pointer and that is the only reference
to that pointer you actually want let's
take a look at an example
a unique pointer so the first thing
you'll need to do to get access to all
these smart pointers is include memory
now we have this entity class here or
what is is the constructor on a
destructor with print when we create the
entity R when we destroy the entity just
so that we can kind of look into the
behavior of these smart pointers so over
here in main if I want to create a
unique pointer which lasts in a certain
scope so I've made a new scope you an
empty scope inside here I'm going to
allocate my entity using a unique
pointer the way I'll do that is I'll
type in SV unique pointer I'll give it a
template argument of entity and then
I'll give it a name such as entity and
then I've kind of got two options I
could either call the constructor here
and type in new entity like this note
that you actually won't be able to do
this kind of construction because if you
look at unique pointer the constructor
is actually explicit meaning that you do
have to call the constructor explicitly
there's no implicit kind of conversion
or converting constructor so that's one
way to make unique point and then you
can kind of access it like you would
anything else if I wanted to call a
function here we don't even have any
functions but if I were to call a
function here I would just access it
through the arrow operator and
everything would be exactly the same as
if this was just a roll pointer the
preferred way though to construct this
would actually be to assign it to STD
make unique with that entity there the
primary reason that that's important for
unique pointers is actually due to
exception safety we'll talk about
exceptions at some point in this series
I don't like exceptions at all so that's
gonna be an interesting episode whenever
that happens but anyway the preferred
way to make this is to call make unique
because it is slightly safer if if the
constructor happens to throw an
exception you weren't end up having a
dangling pointer with no reference and
that's a memory leak anyway the idea is
that once we make this unique pointer we
can call whatever method we want and
you'll see that if I hit f5 to run my
program our entity gets created here and
then if I hit f10 to get out of this
scope our entity is destroyed now
okay so automatically when this code
ends our entity gets destroyed that's
the simplest my pointer that we have
it's very useful it's got a very low
overhead it doesn't really even have an
overhead it's just a stack allocated
object and when when that stack
allocated object eyes it will call
delete on your pointer and free that
memory the problem with this is as I
meant
if you want to copy that at that point
if you want to kind of share that point
and maybe pass it into a function or
have another class story you're gonna
run into a problem because you can't
copy it and if you take a look at this
if I was to try and make another unique
pointer here called easy row or
something like that and assign it to
entity I actually can't do that and
you'll get kind of an error message here
which looks a bit weird if you go to
this unique point of definition and you
actually scroll down a bit you'll see
that the copy constructor and the copy
assignment operator are actually deleted
which is why you get a compile error if
you try and do something like this and
that's that's there specifically to
prevent you from digging yourself into a
grave because you cannot copy this
because because again as soon as one of
these unique pointers dies they all
essentially kind of die because the
memory the underlying memory of that
peepal gated object gets freed so if you
like sharing that's where shared pointer
comes in and share pointer kind of works
a bit a bit differently it's a bit more
hardcore if you will because it does a
lot of other stuff under the hood the
way that a shared pointer is implemented
is actually kind of up to the compiler
and the standard library that you're
using with your compiler however in
pretty much all systems that I've seen
it's it's using something called
reference counting we're gonna have a
specific video about reference counting
and in fact a lot of these things in the
standard library we're actually gonna
have videos where we implement them
ourselves because they're great examples
of how C++ works and how we can kind of
use C++ so we're going to definitely
write our own unique bonus montoya
shared point all of that kind of stuff
in the future as well as other kind of
satellite bury features so if you if you
want that that's coming but the way the
shared pointer works is via reference
counting and reference counting is
basically a practice where you keep
track of how many references you have to
your pointer and as soon as that
reference count reaches zero that's when
it gets deleted so as an example I
create one shared pointer I then create
another shed pointer and copy that my
ref count is now two so one for the
first one once the second one that's two
when the first one dies my reference
count goes down one so I'm on one now
and then when the last one dies my
reference count goes back to zero and
I'm dead
so the memory gets freed so to use a
shared pointer you just type in STD
shared point I'll I'm just get rid of
this compile error will do NC over here
as the template parameter
I'll do shared entity as the
and I'll set this equal to STV make
shared MT now in this case you could
have also done a new entity like this
and you can see if that compiles fine
except you definitely don't want to do
that with shared pointer with unique
points are really the only reason not to
call new directly is because of
exception safety built with shared
pointer there's actually going to be a
difference because shared pointer has to
allocate another block of memory called
the control block where it stores that
reference count and if you create if you
first created a new entity and then pass
it into the shared pointer constructor
it has to allocate that's test2
allocation that's right because you
constructing the entity first and then
be shared pointer has the controller cut
it has to construct its control block
whereas if you do make share it can
actually construct them together which
is a lot more efficient and also for
those of you people who hate new and
delete this obviously gets rid of the
new keyword from your codebase because
you're just calling a city make shared
instead of new entity so I bet you guys
love that
so with shared pointer you can of course
copy it and yeah I mean if I type in
code like this it's gonna work perfectly
fine I could also move this outside to
here and just have this over here let's
let's make another scope for fun so I
can kind of demonstrate how this works
and you drag this over here alright so
I've got kind of two scopes again the
first one I've got is 0 that's it and
then in this one I have my shed entity
I'm going to assign easier with my shed
entity I'm just going to comment out all
get rid of all that other code with the
unique pointer so now what will happen
is if I hit f5 the first thing that's
gonna happen is I'm going to construct
my entity so that's done good it's
created I'm going to assign this when
the first coat dies this challenge she
dies however you can see that it hasn't
destroyed my HT it hasn't deleted it
because a 0 is still alive at holding a
reference to that entity now when I have
10 that's when it dies when all the
references are gone when all of the
stack allocated kind of objects that
keep track of all the shared pointers
when they die when they get read from
memory all of them that's when your
underlying entity gets deleted all right
and finally there's something else that
you can use with shared points are
called
a weight pointer and what you can do
with that is just declare it like it was
anything
and kind of give it the value of a share
density and what this does what this
does is kind of the same as if you were
to copy that share entity and increase
the ref count except it doesn't
including it doesn't increase the ref
count when you assign a shared pointer
to another shared pointer thus copying
it it will increase the ref count but
when you assign a shared pointer to a
weak pointer your orange increase the
ref count so this is great for if you
kind of don't want to take ownership of
the entity like you might be storing a
list of entities and you don't really
care if they're valid or not but you
just want to store like a reference to
them right with weak pointer you can
kind of ask it hey is this is this still
even alive and if it is you can do
whatever you need to do but it won't
keep it alive because it doesn't
actually increase the ref count meaning
that if I worst was to actually replace
this shed and see where the weak pointer
and then basically did the exact same
thing that I did before then the entity
will get credit here
it'll get assigned to the shed and see
but when I exit the first car that is
what it gets destroyed so this weight
pointer is now pointing to an invalid
and T however you can ask a weak pointer
are you expired
are you still valid so that's pretty
much smart pointers now as for when you
should use them you should probably try
and use them all the time if I'm being
completely honest they automate your
memory management they they they get rid
of all they did they prevent you from
accidentally leaking memory by
forgetting to call delete they're really
quite useful shared pointer specifically
has a bit of an overhead because of its
reference counting systems but then
again a lot of people a lot of people
who tend to write their own memory
management systems tend to have a bit of
an overhead as well so it's kind of it's
a very delicate topic because you have
this new breed of C++ programmers now
who only use these kind of features and
then you have like the optical people
who using you and delete I'm kind of a
bit of both because there is a time
where you want to use unique pointer or
shared point two perhaps but there's
also a time where you need new and
delete so don't think that this has
completely replaced you in delete in my
opinion it has absolutely not replaced
new and delete it's just something that
you should probably do when you just
need to declare a heap-allocated object
and you don't particularly want to tidy
up after yourself because you don't need
to kind of explicitly call to later
explicitly manage that memory in those
cases you should be using a smart
pointers usually use unique pointer
whenever you can because it has a lower
overhead but if you absolutely need to
share between objects so you just can't
use any
just can't use a unique pointer then use
a shared pointer but definitely going
that order first you think pointer first
preference share point a second
preference hope you guys enjoy this
video if you did even if that like
button on our YouTube check I said it
was like the said it was there last time
but now it's like in the middle it's
like here or something out in our anyway
you can click that like button if you
enjoyed this video leave any suggestions
you have for future videos and all that
in the comment section below as well as
any questions you may have
I have a discord server where you can
also ask questions link in the
description below and if you really like
this video and you like this series and
you want to support it you want to see
more videos then you can go to
patreon.com/scishow turner pick up some
sweet rewards by helping to support this
series I will see you guys next time
goodbye
[Music]
5.0 / 5 (0 votes)