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