[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)