4 ms·
When I think about C++ "smart" pointers, I often think about easy to provoke / difficult to spot fatal edge cases. E.g. - C++ code where some method calls std
by dvdkhlng 6y ago
When I think about C++ "smart" pointers, I often think about easy to provoke / difficult to spot fatal edge cases. E.g.
- C++ code where some method calls std::shared_from_this(), and that method ends up being called indirectly during the object's construction, leading to a 0-pointer dereference [1]
- accidentally creating two shared-pointers to the same object leading to an eventual double-free (that may just silently corrupt the heap while the program continues running)
- undetectable cyclic shared_ptr<> references somewhere deeply hidden in the code causing a memory leak
Modern C++ feels like a case of "but we can do that in C++, too" syndrome. Stuff that "just works" in Java or Lisp, can now be done in C++, too, however in C++ it will only work for 95% of all use cases, and break in a spectacular manner for the remaining 5%.
E.g. think about the template meta-programming madness (and efficiency WRT compile-time) and compare that with what Lisp offers (see also [2]).
[1] https://stackoverflow.com/questions/31924396/why-shared-from-this-cant-be-used-in-constructor-from-technical- https://stackoverflow.com/questions/31924396/why-shared-from...
standpoint
[2] http://people.cs.uchicago.edu/~jacobm/pubs/templates.html http://people.cs.uchicago.edu/~jacobm/pubs/templates.html
- pierrebai 6y agoBoth of your first two cases exist when people convert code bases that used raw pointers to shared_ptr. The normal intended usage of shared_ptr is to use make_shared and never have a raw pointer ever exist. The need to us shared_from this (or create a new independent shared ptr) happens only because some part of the code base is still using raw pointers for that particular class. OTOH, C++ needs the ability to support old code bases because of its age. Of course a new language can forego this. As for cycles, for GC language using ref-counting under the hood, the same problem applies. I've also seen memory leak from accidental keeping of pointers in fully GC languages. I've seen it happens in Java multiple times. Of course, two wrongs don't make right, but in this case GC is only solving one case. But the more fundamental issue at play is that pointer cycles usually means a lack of up-front design and thought about how a program will work. As such, it is bad, but only a symptom of a lack of proper initial design which can manifest itself in all kind of places.
- dvdkhlng 6y agoI think for shared_from_this() I have a different use-case in mind: an object of some class wants to register with some other class. I.e. think about something like auto self = shared_from_this(); document.onclick([self](){self->doit(); } ); I'm not sure there is a way to express that in C++ without use of enable_shared_from_this. It is very easy to accidentally run this kind of code from a constructor where shared_from_this() is a 0-ptr. make_shared also only helps in 95% of cases. E.g. it does not allow specifying a custom deleter, which is a use-case that is allowed by the shared_ptr<> constructor. It also won't fix any of the problems WRT shared_from_this() being called in the constructor.