Super engaging video as always, the twist in the middle is exactly what I love about your style! You don't just take the standard library for granted as a blackbox. I love that you take us with you into the scary dark depths of standard libraries (be it Python or C++) while still not overwhelming us, thanks and looking forward to more C++ videos ☺
At 5:44 is precisely where I am uncomfortable with C++ as a language. In Haskell, I've explained my mental model of how things would work, and then found out that's *exactly* what they were in the standard library. C++ is a developing language, and here people are actively maintaining it to be unmanageable. There are corner cases in the compiler and language that the library writers have to work around, making the source more complex, slowing the compilation further. It is counter to the purpose of communicating an algorithm between programmers, readers and computers.
Teaching a C++ std feature by implementing it ourselves is exactly how I was taught std::vector at university. This reminded of that professor. Great video as always!
my data structure classes was literally the professor implementing every single data structure you can imagine in python even if most of them already exist in the standard python library.
I'd love a full video dedicated to your comment "standard library implementers have to write it like this for... reasons" @ 5:45. I know that it might be a little different from what you usually post, but I've actually often wondered about this
@@illyias as he implies in the video, it's because the standard library implementers need to worry about the general solution so that the object will work for whatever random thing a programmer tries to throw at it. A simple implementation can ignore all the fiddly bits and simplify it to store nicely behaved objects. How it works is (more than) a bit complicated, but the why is fairly easy to understand.
There are a couple of reason why STL implementations are generally considered "unreadable": - they must use the reserved naming scheme with two leading underscores (__foo) or a leading underscore and a capital letter (_Foo) in order to avoid naming collisions. You're not allowed to use these yourself btw, it's considered undefined behavior - most C++XY specific features and parts of the code in the headers are guarded by ugly macros. - a lot of SFINAE and template tricks are used in the implementation (see std::enable_if and tag dispatching) - micro-optimizations that are not always trivial to understand and that are usually guarded by static checks (see previous point). - conditional noexcept(...), explicit(...) specifiers which turn function definitions into an ugly mess.
C++ devs: you can use std::unique_ptr to reduce the number of bugs from the the most common manual memory management mistakes C devs: just don't make mistakes
The only small thing I'd like to note that not many people know about is that delete already has a built-in check for nullptr, so the repeated checks there are redundant. Other than that 10/10 implementation
Thanks for pointing this out! This is what I was trying to say but maybe I wasn't clear enough. I used an if check even though it is not needed in anticipation of custom deleters, which may not allow deleting nullptr.
Good call doing the exercise of writing the diy unique_ptr class. It shows that you remember what it was like to not understand. The best teachers never forget what it was like to struggle as a n00b.
Very nice explanation! I've not done much C++ so a lot of stuff like this just feels alien to me; walking through the behind the scenes is a great way to show how it works.
Ah i remember converting code to C++11 and needing to convert auto_ptr code to unique_ptr code. But unique_ptr is very useful when inheritance is involved, or for weird pointers like pointers o functions, which you cannot just replace with a member variable... (Can be used as nullable member variable)
I would try and be funny and come up with some reference in the comments, but maybe I'm not smart enough, oh well ;) Def. looking forward to a possible shared_ptr video though!
I feel like every coding channel should have an anonymous bulletin board where people can post code and ask questions. Like a godbolt page or something, that way we wouldn't have to be hindered by RUclips's dislike of external URL's. Although, I suppose it could get out of hand when a channel has over 100k subs. Not everyone asks a question, but if it were easier to do so anonymously, I'd wager you'd get 10 times as many.
unique_ptr is so simple, yet so useful! However my professor still uses "new" and probably does not even know about smart pointers... I personally think that using "new" should become the new "goto".
@@anon1963 Common misconception, why should you start learning way that is not recommended? I know most of us learned new first (because smart pointers did not exist), but there is no good reason. What if memory management is not always the *first* thing you should learn?
@@mattiaslaserskold137 memory management is never the first thing you learn because you should avoid using pointers as much as possible, regardless if it's raw or smart pointer. if you don't need to learn about pointers go use Rust/Python/Java. because if pointers or memory management are not your second nature, you're not getting a job in C/C++ dev.
Yes you already expressed your opinion in the first comment. Now you just repeat yourself. Of course you don't know c++ before you know pointers. In my experience many people think you should first learn c before you start learning c++ and then never get to learn the stuff you should use in production. But why is that? It's only because it's how many old people learn c++, and in Academia, most people use c instead of c++ anyway so that explains why professors think you should use only c features. And if you are a noob c++ developer landing a c++ job in a new code-base, you should not be using new or delete anyway, so why start using it the first thing when learning the new language?
@@mattiaslaserskold137 because you know how smart pointers actually work, but i guess not many of you think critically and remembering that new returns a pointer takes too much space in brain. i understand. i will repeat myself once more then: you wont get a job in c++ without knowing what pointers are and how to use them without smart pointers, ever.
I remember my first contact with unique poiters. I always had problem with this that it never wanted to work properly. And i had copy error despite i couldnt get where copy could be made. Then i was also afraid of memory leaks. Because i learned to analize code line by line, what makes easy to read even messy code, but it triggers alerts automaticly when you don't see something. And i remember when i shouted on some people when i saw make_unique or unique ptr and then i couldn't find any functions or methods deleating it. I was always like "You want to make memory leak?! There is no relese of memory in this code!". And "THERE" was key word. Despite i know how destructors works, I was afraid something can go wrong, just destructor wont be made properly f.e. When i saw source code and i spend few hours moving across this mess i could see that using unique ptr will be safe. It sounds kinda wreid, but sometimes getting knowledge from scratch is better than getting everything as it is said, cause someone can lie.
What happens to the moved pointer if the variable holding it gets dropped if its in a smaller scope? Does the vector size change when moving it? What happens if you try to access it from the vector?
Move constructing a unique_ptr results in leaving the old unique_ptr in a valid-but-unspecified state. I believe all major implementations make that valid-but-unspecified state holding a nullptr, so your vector would end up holding a unique_ptr to nullptr. It does not remove the moved-from unique_ptr from the vector. Accessing the unique_ptr would be fine, you could e.g. reset it to own a new thing if you wanted, but dereferencing it would be dereferencing a nullptr if you didn't reset it first.
@@mCoding Actually slightly incorrect. Move constructing *in general* leaves the old object in a valid-but-unspecified state. However, for unique_ptr *in particular*, the state is specified! The standard requires a moved from unique_ptr to contain nullptr.
In the code seen at ~4:10, what if use_widget was a function expecting to take ownership of the raw pointer being passed in (i.e. it deletes it before it returns)? I understand that passing in get() would be a bug since the underlying raw pointer would become unusable (since it's deleted) and would be double-deleted whenever the smart pointer is destructed. As suggested later in the video, the correct thing to do is to instead pass release() but you still need to know/remember/respect the contract of the function (which is not implied by a signature with Widget* as a parameter) that it deletes the pointer it's passed. I've heard advice (I think Jason Turner?) that you absolutely _should_ refactor functions to take a unique_ptr parameter when they take ownership in this way. Saying your parameter is a unique_ptr (and therefore forcing your caller to std::move it in) very explicitly states that the function claims (unique) ownership of that argument.
Yes absolutely! Code involving ownership of the pointer, such as code that previously deleted or newed objects would need to be refactored to use unique_ptr. It's just the code in the middle (between new and delete) that just uses the pointer that shouldn't need refactoring.
And as always, good documentation is key. Which I would count your last sentence of having the parameter specifically be a unique_ptr to be the documentation.
yeah modern c++ is the shit. good video 👍 ive implemented my own array type using smart pointers and it was nice to see a video on something ive recently wanted to learn about
You could create a series where you re-implement the STL in a way that's easier to understand. It would be a valuable reference for better comprehension. You could name it KISS, which stands for "Keep It Simple, Stupid".
Oh gosh, the opening sentence. Thus should be the first sentence in all cpp materials out there. Every time the language comes up everybody talk it down like it is 2003 again.
Hi, great video and style, but I don't get the argument behind vector of pointers instead of vector of actual objects - due to class inheritance hierarchy. What do you mean by that? How is inheritance related to pointers decision? Thanks!
Thank you! A subclass may not have the same size as its parent, so you can't store them in the same vector, but you can store pointers to those objects. You could use a vector of variants/unions instead, but a vector of pointers tends to be more commonly used, though both approaches fit different situations.
In reset method(8:14) why didn't you delete m_ptr first before assigning ptr(no need for std::exchange)? At first I thought it was in case delete threw, ptr would be deleted but if that happened then: 1. it would result in undefined behavior 2. reset is noexcept so std::terminate would be called which doesn't call any destructors(I'm not sure)? So either it's for future Deleter or I'm just too focused on 'optimizing'. After checking GCC with -O2 flag makes almost identical assembly code.
It's basically just a shorthand for "using" std::move twice. I used quotes to point it out and say that I don't mean the keyword using, but rather the English verb.
See stackoverflow.com/questions/69006612/stdunique-ptr-reset-order-of-operations for discussion. It has to do with (admittedly questionable) cases where an object holds the unique pointer that owns the object. You could perfectly well not support this kind of situation if you wanted and that would be a fine design decision.
What about multi-threading? For one of my old projects I was using unique_ptrs with one thread handling the creation and deletions and another looping though. I ended up using mutexs but I really didn't like that.
All Python objects are effectively shared_ptr's (although literally CPython is written in C, not C++). They have pointer semantics and use reference counting to determine when to free the pointers under the hood, which is exactly what shared_ptr does.
Good idea. Generally, the more you can avoid the heap or dynamic allocation, the better. However for beeg objects/arrays, you will start brushing up against stack size limits. Or sometimes there are cases where the API you are using demands that the object you make survives past the return of the function that currently owns it, but not by a return value. (Such an API I would question the design of, but you don't always get a choice) In these cases, yea, you gotta get your hands dirty with pointer-ish stuff. Though as shown, smart pointer objects help a lot with this.
@@TechSY730 Sure, but the internal implementation can still heap allocate. What you put on the stack in an instance like this is merely a wrapper around the meat of the object. Say an array class of some kind would store a pointer to the data, so what's on the heap is just a couple of unsigned integers and a pointer to whatever type you're storing in that array class.
04:24 - "...all the code in the middle ... should not changed" - isn't better to add `use_widget(std::shared_prt widged)` instead `use_widget` with "raw" pointer?
This is a common misconception. Keep in mind that shared_ptr incurs a significant runtime cost due to atomic reference counting. It is the best choice in some situations, especially when multiple unrelated parts of the code need to keep an object alive. But if you can determine a unique owner whose lifetime encapsulates the lifetime of the pointed to object, then you should not need to change code to take shared_ptr or even unique_ptr except for code that deals with managing the lifetime. Code that simply needs a Widget should continue using raw pointers and references.
Great question! In C++, a pointer is not nullptr if and only if it is nonzero, so if (p) and if (p != nullptr) are semantically identical, although you may prefer to use one over the other for stylistic reasons.
@@mCoding Actually, I write either in Python or C++ and don't understand when I can use both languages. You are always showing great examples, so I thought you know when it is useful. Also, it is interesting how to write extensions that release GIL.
new to c++ why is there struct and class? does struct just not have methods, only structure? also, any practical reason to use ++i instead of i++. also i dont really get how all these "widgets" work
Unique pointer is supposed to have unique ownership of the pointer. Reset says, here's a raw pointer that I own, I would like the unique pointer to own it now. Resetting a unique pointer to the pointer it already owns would be a contract violation, and unlikely to come up on any normal code. Might be nice to assert on it in debug builds, but it makes sense that they don't waste cycles checking for it normally. The more general problem of resetting the unique pointer to a pointer it doesn't actually uniquely own can't really be detected without sanitizers.
Yes of course, but the point he's making is that you still have to _remember_ to write that try/catch block and properly handle the case where the vector elements are only partially constucted.
C++ has try/catch, but it does not have try/finally. The purpose of try/finally is to ensure resources are cleaned up, but in C++ this is the purpose of destructors, so C++ does not include try/finally, forcing you to use a destructor instead. The design decision is widely criticized but unlikely to change.
Actually, there is a way to write code to gracefully handle partial construction and proper cleanup: aHR0cHM6Ly9naXRodWIuY29tL2xkby9hX3N0cnVjdHVyZWRfZGlzY2lwbGluZV9vZl9wcm9ncmFtbWluZy8=
@@lawrencedoliveiro9104 Interesting example, but what about say an array of objects with each needing instantiation and all previous objects needing cleanup in case one fails at some point in the middle of instantiation of the array? Obviously PyObjects will be fine, since IIRC it uses GC, but what about objects not managed by Python? Also, while I understand the desire to eliminate goto, I don't really agree with it. For each allocation action I use inside a function I add a label at the end to handle that case then merely goto that label in an incrementing manner. I find it easier to read than a series of nested do/while(false) loops, but that may just be me.
@@anon_y_mousse My examples did not rely on Python’s garbage collection to clean things up: the point of the code structure is to manage all this explicitly, yet in an easy-to-manage, easy-to-understand way. And yes, avoiding gotos falls naturally out of this control discipline.
I have to disagree with your statement about smart pointers being used in the same way as a normal pointer. As an example, returning a pointer from a function: if you use a smart pointer, you need to be aware of copy elision. Secondly, if you want to return say a tuple or a pair and one of them is a smart pointer, you're going to need to invoke std::move. This is before you even get into having to use get() to get the actual pointer. What about defining a custom destructor for the smart pointer? So, how are these like pointers? Yup, they're not.
You said a copy would make 2 objects own the same pointer. But thats not necessary true. Not if you make it do a deep copy. You say it like the only way to do it is do a shallow copy. Why did you ignore that deep copies exist and act like only shallow copies exist?
Great question! This video is about unique_ptr, which (like most pointer types) is supposed to have "pointer semantics". Pointer semantics implies that a copy of the pointer should just copy the address of the value, not copy the value itself. It is uncommonly used, but what you describe is effectively a pointer that has "value semantics" instead of pointer semantics. With value semantics, copying means you get a true (deep) copy. You can find implementations of such pointers by searching "value_ptr".
I'm not sure what you mean by unique ptr does not support polymorphism. If you have a unique ptr to a derived object and call a virtual function, it will call the derived version of the function. It exhibits the same behavior as a raw pointer does with respect to polymorphism. Perhaps you forgot to mark your destructor or other function virtual?
Which is better, more syntax or more code? Consider that if syntax is added to the language that it can't be changed as easily as mere code and provides a barrier to entry for new programmers because now they have to look up a symbol to determine what it means instead of looking up a whole word. Also consider that these concepts were thought up long before Rust existed and it's just copying a good concept from better programmers, albeit with horrible syntax additions.
More c++ please!! Incredible video as always
Thank you very much and I'll get right on it!
Agreee!!!
^ Ditto
How about Google’s “Carbon” project? That is trying to simplify C++.
0:22
Super engaging video as always, the twist in the middle is exactly what I love about your style! You don't just take the standard library for granted as a blackbox. I love that you take us with you into the scary dark depths of standard libraries (be it Python or C++) while still not overwhelming us, thanks and looking forward to more C++ videos ☺
Thanks very much for your kind words!
At 5:44 is precisely where I am uncomfortable with C++ as a language. In Haskell, I've explained my mental model of how things would work, and then found out that's *exactly* what they were in the standard library. C++ is a developing language, and here people are actively maintaining it to be unmanageable. There are corner cases in the compiler and language that the library writers have to work around, making the source more complex, slowing the compilation further. It is counter to the purpose of communicating an algorithm between programmers, readers and computers.
Teaching a C++ std feature by implementing it ourselves is exactly how I was taught std::vector at university. This reminded of that professor. Great video as always!
my data structure classes was literally the professor implementing every single data structure you can imagine in python even if most of them already exist in the standard python library.
I'd love a full video dedicated to your comment "standard library implementers have to write it like this for... reasons" @ 5:45. I know that it might be a little different from what you usually post, but I've actually often wondered about this
Given the look on his face, I think he was implying that he doesn't know the reasons himself, he just knows there's a reason for it.
@@illyias as he implies in the video, it's because the standard library implementers need to worry about the general solution so that the object will work for whatever random thing a programmer tries to throw at it. A simple implementation can ignore all the fiddly bits and simplify it to store nicely behaved objects. How it works is (more than) a bit complicated, but the why is fairly easy to understand.
There are a couple of reason why STL implementations are generally considered "unreadable":
- they must use the reserved naming scheme with two leading underscores (__foo) or a leading underscore and a capital letter (_Foo) in order to avoid naming collisions. You're not allowed to use these yourself btw, it's considered undefined behavior
- most C++XY specific features and parts of the code in the headers are guarded by ugly macros.
- a lot of SFINAE and template tricks are used in the implementation (see std::enable_if and tag dispatching)
- micro-optimizations that are not always trivial to understand and that are usually guarded by static checks (see previous point).
- conditional noexcept(...), explicit(...) specifiers which turn function definitions into an ugly mess.
@@cristian-si1gb thank you!
@@cristian-si1gb God damn, this dude knows his shit
Me looking at the standard template library:
"Seems.... to be made of.... code"
C++ devs: you can use std::unique_ptr to reduce the number of bugs from the the most common manual memory management mistakes
C devs: just don't make mistakes
C devs: We write the Linux kernel.
C++ devs: What’s a kernel?
@@lawrencedoliveiro9104 you could write an os in c++, no problem
Haiku OS and the Zircon kernel use C++
@@ccgarciab Neither of which are known for high performance.
rewrite it in rost
The only small thing I'd like to note that not many people know about is that delete already has a built-in check for nullptr, so the repeated checks there are redundant. Other than that 10/10 implementation
Thanks for pointing this out! This is what I was trying to say but maybe I wasn't clear enough. I used an if check even though it is not needed in anticipation of custom deleters, which may not allow deleting nullptr.
C++ is always a welcome topic. Would love some shader languages as well
Good call doing the exercise of writing the diy unique_ptr class. It shows that you remember what it was like to not understand. The best teachers never forget what it was like to struggle as a n00b.
"Let's write unique pointer." Fuck. Yes.
Fantastic teaching method
I liked the additional information where you created the unique_ptr yourself.
this is definitely the best unique pointer video on youtube.
Thanks! I appreciate it!
Very nice explanation! I've not done much C++ so a lot of stuff like this just feels alien to me; walking through the behind the scenes is a great way to show how it works.
Ah i remember converting code to C++11 and needing to convert auto_ptr code to unique_ptr code.
But unique_ptr is very useful when inheritance is involved, or for weird pointers like pointers o functions, which you cannot just replace with a member variable... (Can be used as nullable member variable)
I would try and be funny and come up with some reference in the comments, but maybe I'm not smart enough, oh well ;)
Def. looking forward to a possible shared_ptr video though!
Laughs in rust 🦀.
Jokes aside. Really interesting video. Love it ❤
unsafe { laughs in C++; }
Appreciate it!
C++>>>>>>>>
This is very clear and thanks for the implementation details. It help a lot to understand what is going on
I feel like every coding channel should have an anonymous bulletin board where people can post code and ask questions. Like a godbolt page or something, that way we wouldn't have to be hindered by RUclips's dislike of external URL's. Although, I suppose it could get out of hand when a channel has over 100k subs. Not everyone asks a question, but if it were easier to do so anonymously, I'd wager you'd get 10 times as many.
More modern / post-modern C++ please!♥
unique_ptr is so simple, yet so useful! However my professor still uses "new" and probably does not even know about smart pointers... I personally think that using "new" should become the new "goto".
because as a decent programmer you need to know how to manage memory yourself, and know what new, delete are
@@anon1963 Common misconception, why should you start learning way that is not recommended? I know most of us learned new first (because smart pointers did not exist), but there is no good reason. What if memory management is not always the *first* thing you should learn?
@@mattiaslaserskold137 memory management is never the first thing you learn because you should avoid using pointers as much as possible, regardless if it's raw or smart pointer. if you don't need to learn about pointers go use Rust/Python/Java. because if pointers or memory management are not your second nature, you're not getting a job in C/C++ dev.
Yes you already expressed your opinion in the first comment. Now you just repeat yourself.
Of course you don't know c++ before you know pointers. In my experience many people think you should first learn c before you start learning c++ and then never get to learn the stuff you should use in production. But why is that? It's only because it's how many old people learn c++, and in Academia, most people use c instead of c++ anyway so that explains why professors think you should use only c features.
And if you are a noob c++ developer landing a c++ job in a new code-base, you should not be using new or delete anyway, so why start using it the first thing when learning the new language?
@@mattiaslaserskold137 because you know how smart pointers actually work, but i guess not many of you think critically and remembering that new returns a pointer takes too much space in brain. i understand. i will repeat myself once more then: you wont get a job in c++ without knowing what pointers are and how to use them without smart pointers, ever.
Thanks! Very, very helpful!!
I would love to see a follow-up video on custom deleters.
I remember my first contact with unique poiters. I always had problem with this that it never wanted to work properly. And i had copy error despite i couldnt get where copy could be made.
Then i was also afraid of memory leaks. Because i learned to analize code line by line, what makes easy to read even messy code, but it triggers alerts automaticly when you don't see something.
And i remember when i shouted on some people when i saw make_unique or unique ptr and then i couldn't find any functions or methods deleating it. I was always like "You want to make memory leak?! There is no relese of memory in this code!". And "THERE" was key word. Despite i know how destructors works, I was afraid something can go wrong, just destructor wont be made properly f.e.
When i saw source code and i spend few hours moving across this mess i could see that using unique ptr will be safe.
It sounds kinda wreid, but sometimes getting knowledge from scratch is better than getting everything as it is said, cause someone can lie.
I know what you mean, it's part of what gave me the negative guttural reaction to first seeing Java code, new everywhere, no delete.
why do you use m_ptr{other.release()} instea of m_ptr(other.release()) ?
What happens to the moved pointer if the variable holding it gets dropped if its in a smaller scope?
Does the vector size change when moving it?
What happens if you try to access it from the vector?
Move constructing a unique_ptr results in leaving the old unique_ptr in a valid-but-unspecified state. I believe all major implementations make that valid-but-unspecified state holding a nullptr, so your vector would end up holding a unique_ptr to nullptr. It does not remove the moved-from unique_ptr from the vector. Accessing the unique_ptr would be fine, you could e.g. reset it to own a new thing if you wanted, but dereferencing it would be dereferencing a nullptr if you didn't reset it first.
@@mCoding Actually slightly incorrect. Move constructing *in general* leaves the old object in a valid-but-unspecified state. However, for unique_ptr *in particular*, the state is specified! The standard requires a moved from unique_ptr to contain nullptr.
Suggestion. Rvalue Lvalue and move operations from scratch without STL.
All move does is casting to rvalue
Great video as always! How long have you been coding?
Great video as always! I'd love a video on CPython vs PyPy (and any other alternative python implementations). Thanks!
In the code seen at ~4:10, what if use_widget was a function expecting to take ownership of the raw pointer being passed in (i.e. it deletes it before it returns)? I understand that passing in get() would be a bug since the underlying raw pointer would become unusable (since it's deleted) and would be double-deleted whenever the smart pointer is destructed. As suggested later in the video, the correct thing to do is to instead pass release() but you still need to know/remember/respect the contract of the function (which is not implied by a signature with Widget* as a parameter) that it deletes the pointer it's passed.
I've heard advice (I think Jason Turner?) that you absolutely _should_ refactor functions to take a unique_ptr parameter when they take ownership in this way. Saying your parameter is a unique_ptr (and therefore forcing your caller to std::move it in) very explicitly states that the function claims (unique) ownership of that argument.
Yes absolutely! Code involving ownership of the pointer, such as code that previously deleted or newed objects would need to be refactored to use unique_ptr. It's just the code in the middle (between new and delete) that just uses the pointer that shouldn't need refactoring.
And as always, good documentation is key. Which I would count your last sentence of having the parameter specifically be a unique_ptr to be the documentation.
GREAT video!
Thanks a lot sir
yeah modern c++ is the shit. good video 👍
ive implemented my own array type using smart pointers and it was nice to see a video on something ive recently wanted to learn about
You could create a series where you re-implement the STL in a way that's easier to understand. It would be a valuable reference for better comprehension. You could name it KISS, which stands for "Keep It Simple, Stupid".
SSTL, Simple Standard Template Library.
Oh gosh, the opening sentence. Thus should be the first sentence in all cpp materials out there. Every time the language comes up everybody talk it down like it is 2003 again.
rip auto_ptr
He who shall not be named
@@mCoding hahhahah
7:20 i use lots of this sort of thing for my opengl project where i have a glGen*(1, &...); call followed by a glDelete*(1, &...); in the destructor
Hi, great video and style, but I don't get the argument behind vector of pointers instead of vector of actual objects - due to class inheritance hierarchy. What do you mean by that? How is inheritance related to pointers decision? Thanks!
Thank you! A subclass may not have the same size as its parent, so you can't store them in the same vector, but you can store pointers to those objects. You could use a vector of variants/unions instead, but a vector of pointers tends to be more commonly used, though both approaches fit different situations.
More C++ please 🙏
5:11 meanwhile me doing my C assignment in assembly and then using `asm()` for everything
Wouldn't it be a good habit to default initialize m_ptr to nullptr like `T *m_ptr { nullptr };'?
In reset method(8:14) why didn't you delete m_ptr first before assigning ptr(no need for std::exchange)?
At first I thought it was in case delete threw, ptr would be deleted but if that happened then:
1. it would result in undefined behavior
2. reset is noexcept so std::terminate would be called which doesn't call any destructors(I'm not sure)?
So either it's for future Deleter or I'm just too focused on 'optimizing'.
After checking GCC with -O2 flag makes almost identical assembly code.
It's basically just a shorthand for "using" std::move twice. I used quotes to point it out and say that I don't mean the keyword using, but rather the English verb.
See stackoverflow.com/questions/69006612/stdunique-ptr-reset-order-of-operations for discussion. It has to do with (admittedly questionable) cases where an object holds the unique pointer that owns the object. You could perfectly well not support this kind of situation if you wanted and that would be a fine design decision.
What about multi-threading? For one of my old projects I was using unique_ptrs with one thread handling the creation and deletions and another looping though. I ended up using mutexs but I really didn't like that.
Does Python have something similar to smart pointers?
All Python objects are effectively shared_ptr's (although literally CPython is written in C, not C++). They have pointer semantics and use reference counting to determine when to free the pointers under the hood, which is exactly what shared_ptr does.
@@mCoding
Similar to Cython.
Makes me realize how out of practice I am with C++, and I think how outdated my C++ was even when I was using it.
Today is always the best day to get started practicing!
I've never come across a use for pointers of any kind in c++. I tend to allocate everything on the stack & pass variables by reference.
Need some data that is allocated higher up the stack? Just pass it back down by returning
This is a reasonable thing to do, sometimes even necessary for certain applications e.g. where dynamic allocations are forbidden.
@@mCoding also avoids the need to check for mem leaks ;-) although i guess that's also true when using unique_ptr
Good idea. Generally, the more you can avoid the heap or dynamic allocation, the better.
However for beeg objects/arrays, you will start brushing up against stack size limits.
Or sometimes there are cases where the API you are using demands that the object you make survives past the return of the function that currently owns it, but not by a return value. (Such an API I would question the design of, but you don't always get a choice)
In these cases, yea, you gotta get your hands dirty with pointer-ish stuff.
Though as shown, smart pointer objects help a lot with this.
@@TechSY730 Sure, but the internal implementation can still heap allocate. What you put on the stack in an instance like this is merely a wrapper around the meat of the object. Say an array class of some kind would store a pointer to the data, so what's on the heap is just a couple of unsigned integers and a pointer to whatever type you're storing in that array class.
Make more C++ videos please thank you.
04:24 - "...all the code in the middle ... should not changed" - isn't better to add `use_widget(std::shared_prt widged)` instead `use_widget` with "raw" pointer?
This is a common misconception. Keep in mind that shared_ptr incurs a significant runtime cost due to atomic reference counting. It is the best choice in some situations, especially when multiple unrelated parts of the code need to keep an object alive. But if you can determine a unique owner whose lifetime encapsulates the lifetime of the pointed to object, then you should not need to change code to take shared_ptr or even unique_ptr except for code that deals with managing the lifetime. Code that simply needs a Widget should continue using raw pointers and references.
@@mCoding Thanks for explanation. Just to be on the same page "some situation" it's mostly multithreaded environment, right?
People told me to not use push_back anymore. But instead use emplace_back. You are using vector wrong.
10:06 in the destructor you test on `m_ptr` being non zero. Shouldn't that be a test for it not being nullptr?
Great question! In C++, a pointer is not nullptr if and only if it is nonzero, so if (p) and if (p != nullptr) are semantically identical, although you may prefer to use one over the other for stylistic reasons.
Hi, James. Can you make a video about using C/C++ with Python?
Perhaps, what did you have in mind?
@@mCoding Actually, I write either in Python or C++ and don't understand when I can use both languages. You are always showing great examples, so I thought you know when it is useful. Also, it is interesting how to write extensions that release GIL.
new to c++ why is there struct and class? does struct just not have methods, only structure?
also, any practical reason to use ++i instead of i++. also i dont really get how all these "widgets" work
struct elements are public by default , while class are public
Shouldn't reset() have code to guard against setting the same pointer that was already set?
It's up to you but the real std::unique_ptr does not guard against this.
Unique pointer is supposed to have unique ownership of the pointer. Reset says, here's a raw pointer that I own, I would like the unique pointer to own it now. Resetting a unique pointer to the pointer it already owns would be a contract violation, and unlikely to come up on any normal code.
Might be nice to assert on it in debug builds, but it makes sense that they don't waste cycles checking for it normally. The more general problem of resetting the unique pointer to a pointer it doesn't actually uniquely own can't really be detected without sanitizers.
Welcome to you.
1:49 Doesn’t C++ have the equivalent of try/finally?
Yes of course, but the point he's making is that you still have to _remember_ to write that try/catch block and properly handle the case where the vector elements are only partially constucted.
C++ has try/catch, but it does not have try/finally. The purpose of try/finally is to ensure resources are cleaned up, but in C++ this is the purpose of destructors, so C++ does not include try/finally, forcing you to use a destructor instead. The design decision is widely criticized but unlikely to change.
Actually, there is a way to write code to gracefully handle partial construction and proper cleanup: aHR0cHM6Ly9naXRodWIuY29tL2xkby9hX3N0cnVjdHVyZWRfZGlzY2lwbGluZV9vZl9wcm9ncmFtbWluZy8=
@@lawrencedoliveiro9104 Interesting example, but what about say an array of objects with each needing instantiation and all previous objects needing cleanup in case one fails at some point in the middle of instantiation of the array? Obviously PyObjects will be fine, since IIRC it uses GC, but what about objects not managed by Python? Also, while I understand the desire to eliminate goto, I don't really agree with it. For each allocation action I use inside a function I add a label at the end to handle that case then merely goto that label in an incrementing manner. I find it easier to read than a series of nested do/while(false) loops, but that may just be me.
@@anon_y_mousse My examples did not rely on Python’s garbage collection to clean things up: the point of the code structure is to manage all this explicitly, yet in an easy-to-manage, easy-to-understand way.
And yes, avoiding gotos falls naturally out of this control discipline.
3:20 constructing one yourself vs using std::make_unique are the same, but std::make_unique does have the advantage of being less verbose
How can i upvote this twice
modern c++ gives me a "Hey rust, can I copy your homework" vibes
unique_ptr was introduced in C++11 (around 2011), whereas Rust first appeared in 2015. So who really copied whom? 🤔
any plans on teaching us Rust?
Not at the moment
@@mCoding I'd love to see some Rust content as well
@@mCoding I'd love to see you teach some Rust as well
0:01 just like with Javascript…
This is why Rust is the way
8:56 is the guard even needed here? nothing bad would even happen if the guard is omitted
How about more algorithms and how to solve them in Python or C++? It would be useful, especially for those with no background in CS.
le discord gang as usual
I have to disagree with your statement about smart pointers being used in the same way as a normal pointer. As an example, returning a pointer from a function: if you use a smart pointer, you need to be aware of copy elision. Secondly, if you want to return say a tuple or a pair and one of them is a smart pointer, you're going to need to invoke std::move. This is before you even get into having to use get() to get the actual pointer. What about defining a custom destructor for the smart pointer? So, how are these like pointers? Yup, they're not.
Hi
Hello!
You said a copy would make 2 objects own the same pointer. But thats not necessary true. Not if you make it do a deep copy. You say it like the only way to do it is do a shallow copy. Why did you ignore that deep copies exist and act like only shallow copies exist?
Great question! This video is about unique_ptr, which (like most pointer types) is supposed to have "pointer semantics". Pointer semantics implies that a copy of the pointer should just copy the address of the value, not copy the value itself. It is uncommonly used, but what you describe is effectively a pointer that has "value semantics" instead of pointer semantics. With value semantics, copying means you get a true (deep) copy. You can find implementations of such pointers by searching "value_ptr".
Also unique ptr doesnt support polymorphism though. I tried using it but only sharedptr can
I'm not sure what you mean by unique ptr does not support polymorphism. If you have a unique ptr to a derived object and call a virtual function, it will call the derived version of the function. It exhibits the same behavior as a raw pointer does with respect to polymorphism. Perhaps you forgot to mark your destructor or other function virtual?
Call this C++arcinization because every change that improves C++ makes the Dev evolve into something more like a Rustacean...
Which is better, more syntax or more code? Consider that if syntax is added to the language that it can't be changed as easily as mere code and provides a barrier to entry for new programmers because now they have to look up a symbol to determine what it means instead of looking up a whole word. Also consider that these concepts were thought up long before Rust existed and it's just copying a good concept from better programmers, albeit with horrible syntax additions.
Bruh... use rust.
Doesn't Rust also have the exact same concept? It's just called Box