[HN Gopher] The Myth of Smart Pointers
___________________________________________________________________
The Myth of Smart Pointers
Author : jandeboevrie
Score : 7 points
Date : 2023-11-30 06:47 UTC (16 hours ago)
(HTM) web link (www.logikalsolutions.com)
(TXT) w3m dump (www.logikalsolutions.com)
| aw1621107 wrote:
| > The standard states you cannot make [two] unique_ptr<> with the
| same pointer value within the same compilation unit.
|
| > We got this error because the "compiler will only allow one
| unique_ptr per address" mantra is mostly kaka.
|
| I'm curious where the "enforced one unique_ptr per address" idea
| comes from. I don't think I've ever heard of it before, and I
| don't see any language implying that in the current (?) draft
| standard [0]. If anything, I think I'd be a bit surprised if such
| language existed - after all, creating multiple unique_ptrs to
| the same place is technically harmless as long as you call
| release() on enough of them so you don't end up multi-deleting
| the common object.
|
| This also seems like one of those things where "cannot" is more
| "doing this is a bad idea and you may run into UB" than "the
| program will not compile if you do this" due to guaranteed
| enforcement being statically infeasible.
|
| The other issues including the QML stuff sounds more like unclear
| ownership semantics across libraries. I feel the advice here is
| slightly off-target; if you don't know the ownership semantics of
| the libraries you're using neither using smart pointers nor
| avoiding smart pointers are going to be a magic bullet to solve
| your issues maybe unless you take things to the extreme and
| allocate everything on startup.
|
| > Someone thinks it is a good idea to use Smart Pointers then
| passes the value to library functions written in C and other
| languages. Usually these things are in their own threads.
|
| Like this. The issue isn't the smart pointers, it's that the
| ownership semantics of the library function(s) weren't properly
| accounted for. unique_ptr::release() exists for a reason, after
| all!
|
| > When trying to track down a ghost like crash, _nuke all of the
| Smart Pointers in the code._ Make them raw pointers and delete
| them when you know it is safe.
|
| I'm somewhat surprised this is the advice given rather than
| something like sanitizers and/or valgrind, since those could be
| _significantly_ less invasive than ripping every smart pointer in
| a program. Then again, the author states they work on medical
| devices, and I 'm not sure whether sanitizers or valgrind are
| available for those.
|
| In addition, the second sentence is pretty much "don't write
| bugs", which is technically correct but not exactly helpful; why
| not "look at your smart pointers again and ensure they aren't
| violating their ownership guarantees"? You would basically be
| doing the same thing - lifetime analysis - either way. Heck, you
| can even re-scope your smart pointers so they'll only go out of
| scope "when you know it is safe".
|
| I don't think I've heard "near heap" and "far heap" used in such
| a way before, either. Not that it's bad; just different.
|
| [0]: https://eel.is/c++draft/unique.ptr
| TillE wrote:
| Yeah this just comes across as not understanding pointer
| ownership, or memory allocation in general. It's not a trivial
| issue, especially if you're dealing with weird C libraries.
| Sometimes you don't own a pointer you allocated. Sometimes you
| need a custom deleter.
|
| Within your own code you can just use std::make_unique and rely
| on the compiler to catch errors, but when passing raw pointers
| to libraries you really gotta read the docs and work carefully.
| greiskul wrote:
| Yeah, with the QML example, if the programmer instead had used
| a raw pointer, he would still have a problem. Since if he chose
| to call free, he would have the same crash that the example
| had. And if he chose to just never call free, he would have a
| memory leak.
| kazinator wrote:
| > _Someone thinks it is a good idea to use Smart Pointers then
| passes the value to library functions written in C and other
| languages_
|
| If you got a low-level pointer out of the smart pointer container
| in order to pass to a foreign library, then you're not strictly
| using smart pointers. You violated the encapsulation in order to
| get a "dumb" pointer out, and the issue is related to that.
|
| This is a complete strawman.
|
| "Don't use a garbage collected, managed languages, they are a
| myth. Why? Because a pointer to some garbage-collected object
| ends up in foreign libraries written in C, which can hang on to
| it past reclamation ..."
|
| Well, gee whiz, you will just have to learn about the exact
| sharing situation with the foreign code (how long does it retain
| the object) and do what is necessary.
|
| > _Make them raw pointers and delete them when you know it is
| safe._
|
| That's completely stupid. If you know when it's safe, it means
| you must know when the third party library is no longer using
| them. If you know that, you work that knowledge into the smart
| pointer solution.
|
| Smart pointers, by themselves, have their own idea of when it is
| safe to delete something. That idea is very clear and obvious. If
| it doesn't match the reality of what is safe when, then you have
| to augment the logic. That's it.
|
| If a foreign library directly accesses an object that you track
| with a smart pointer, you can create a proxy object representing
| that library, and that proxy object can hold on to a smart
| pointer on behalf of the foreign library.
|
| The complexity of dealing with the foreign library could be
| entirely minor (and self-contained) compared to the overall
| resource management problem of that smart pointer class; you
| could be making a lot of unnecessary work for yourself (and
| future bugs) by uprooting the smart pointers in favor of dumb
| pointers.
|
| What are you going to do if part of the reason the smart pointers
| are there is that they are providing needed exception safety?
| greiskul wrote:
| Well, yeah, a language feature to improve program correctness
| won't work if you use it wrong. But in both examples, just from
| the interfaces, this should be caught in code review without even
| having to read the libraries being called. Anytime you take a raw
| pointer to a smart pointer owned object, you should question
| yourself, what happens to the lifetime of my object. Because you
| just took the safety off C++s classic footgun of memory
| management, and if you are not extremely careful, you are going
| to lose a foot.
___________________________________________________________________
(page generated 2023-11-30 23:00 UTC)