4 ms·
C++: Where you can accidentally deallocate an object that's still in the call stack. (true story)
by Dwedit 9mo ago
C++: Where you can accidentally deallocate an object that's still in the call stack. (true story)
- einpoklum 9mo agoWell, you can also write: int x = 123; delete &x; and that would compile. But it's not a very good idea and you should be able to, well, not do that. In modern C++, we avoid allocating and deallocating ourselves, as much as possible. But of course, if you jump to arbitrary code, or overwrite something that's due as input for deallocation with the wrong address, or similar shenanigans, then - it could happen.
- kccqzy 9mo agoYou can also do that intentionally and correctly. After all `delete this;` is a valid statement that can occasionally be useful. That said, I’ve only seen this in old pre-C++11 code that does not adhere to the RAII best practice.
- HarHarVeryFunny 9mo agoThe trouble with C++ is that it maintains backwards compatibility with C, so every error-prone thing you could do in C, you can still do in C++, even though C++ may have a better way. The modern, safest, way to use C++, is to use smart pointers rather than raw pointers, which guarantee that nothing gets deleted until there are no more references to it, and that at that point it will get deleted. Of course raw pointers and new/delete, even malloc/free, all have their uses, and without these low level facilities you wouldn't be able to create better alternatives like smart pointers, but use these at your own peril, and don't blame the language if you mess up, when you could have just done it the safe way!
- aw1621107 9mo ago> which guarantee that nothing gets deleted until there are no more references to it, and that at that point it will get deleted. To be more precise, C++'s smart pointers will ensure something is live while specific kinds of references the smart pointer knows about are around, but they won't (and can't) catch all references. For example, std::unique_ptr ensures that no other std::unique_ptr will own its object and std::shared_ptr will not delete its object while there are other std::shared_ptrs around that point to the same object, but neither can track things like `std::span`/`std::string_view`/other kinds of references into their object.
- HarHarVeryFunny 9mo agoI was just talking about ownership and smart pointers. C++'s non-owning "view" classes are a different matter, and the issue there isn't ownership but lifetime of the view vs the underlying data the view is referencing (which in case of string_view could be literally anywhere - a local array of char, a malloc'd block of memory, etc!!). I'm not a fan of a lot of the (relatively) more recent additions to C++. I think C++14 was about the peak! Given that C++ is meant to be usable as a systems programming language, not just for applications, and given that many new features being added to C++ are really library additions, not language ones, then it's important for the language to include unsafe lower level facilities than can be used for things like that, but actually encouraging application developers to use classes like this that are error-prone by design seems questionable!
- aw1621107 9mo ago> I was just talking about ownership and smart pointers. Sure, I was just clarifying that "references" in the bit I quoted covers specific things and not everything with reference-like behavior.
- HarHarVeryFunny 9mo agoSure, I should have been clearer that smart pointers only guarantee not to release things until there are no more SMART POINTER references to them. As soon as you start mix 'n' matching smart pointers and raw pointers into what they are pointing to, then all bets are off!
- HarHarVeryFunny 9mo ago> but neither can track things like `std::span`/`std::string_view`/other kinds of references into their object. Sure, and if you get into it there are two issues here. 1) Smart pointers are a leaky abstraction that still gives you access to the underlying raw pointer if you want, with which you can shoot yourself in the foot. 2) It's not the smart pointer's fault, but the type you use them to point to might also be a leaky abstraction (e.g. std::string, which again allows access to the underlying raw pointer), or might just be some hot garbage the developer themselves wrote!
- simonask 9mo agoThe trouble with C++ is that it maintains backward compatibility with C++.
- HarHarVeryFunny 9mo agoI suppose so, but I think it's relatively rare for languages to just drop support for older features and force developers to rewrite code using newer mechanisms. Python 2 to 3 is a good example of what can be expected to happen - very slow adoption of the new version since companies may just not have the resources or desire to rewrite existing code that is running without problems.
- tialaramex 9mo agoLate in the C++ 20 timeline P1881 Epochs were proposed. Similar to Rust's editions, which at that time had been tried in anger only once (2018 Edition) this proposed that there should be a way for C++ to evolve, forbidding obsolete syntax in newer projects rather than just growing forever like cancer. Epochs was given the usual WG21 treatment and that's the end of that. Rust shipped 2021 Edition, and 2024 Edition, and I see no reason to think 2027 Edition won't happen. The current iteration of Bjarne's "Profiles" idea is in a similar ballpark though it got there via a very different route. This time because it will aid safety to outlaw things that are now considered a bad idea. If this goes anywhere its nearest ship vehicle is C++ 29. Now, Python 2 to Python 3 did take a few years, maybe a decade. But just shipping the mechanism to reform C++ looks likely to take at least nine years. Not the reform, just the mechanism to enable it.
- pjmlp 9mo agoMeanwhile editions still don't have an answer for semantics changes exposed on public APIs for crates, each compiled on its own edition. So what does the compiler chose, the edition of the caller, or the caller?
- tialaramex 9mo ago
- Conscat 9mo agoThe modern safest way to use C++ involves lifetime annotations and ownership annotations run under multiple built-in Clang constraint solvers, but this isn't what most users do.