7 ms·
Understanding C++ Ownership System
- Dwedit 9mo agoC++: 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!
- jesse__ 9mo agoDoes anyone reading this have links to people who have written specifically about a C++ ownership model that rejects the smart_ptr/RAII/friends model in favor of an ownership model that embraces bulk allocations, arenas, freelists, etc? I know there are groups of highly productive programmers that feel the traditional C++ ownership model is hot garbage, and I'd love a resource that puts down specific arguments against it, but I've never come across one myself. Edit: clarity
- rubymamis 9mo agoI'm interested in the same! There are plenty of resources for C[1][2]. I just looked into my old notes and found a post for C++[3]. [1] https://btmc.substack.com/p/memory-unsafety-is-an-attitude-problem https://btmc.substack.com/p/memory-unsafety-is-an-attitude-p... [2] https://www.gingerbill.org/series/memory-allocation-strategies/ https://www.gingerbill.org/series/memory-allocation-strategi... [3] https://dmitrysoshnikov.com/compilers/writing-a-pool-allocator/ https://dmitrysoshnikov.com/compilers/writing-a-pool-allocat...
- jesse__ 9mo agoNice, thanks. I haven't read those gingerbill ones, I'll take a look :D
- otherjason 9mo agoWhat makes you think that RAII- and arena-based strategies are in tension with one another? RAII and smart pointers are more related to the ownership and resource management model. Allocating items in bulk or from arenas is more about where the underlying resources and/or memory come from. These concepts can certainly be used in tandem. What is the substance of the argument that RAII, etc. are "hot garbage?"
- einpoklum 9mo agoIn my library [1], wrapping the CUDA APIs in modern C++, I do allocations which are not exactly from an arena, but something in that neighborhood - memory spaces on context on GPU devices. Unlike the GP suggests, and like you suggest, I have indeed embraced RAII in the library - generally, not just w.r.t. memory allocation. I have not, however, replicated that idioms of the standard library. So, for example: * My allocations are never typed. * The allocation 'primitives' return a memory_region type - essentially a pointer and a size; I discourage the user from manipulating raw pointers. * Instead of unique_ptr's, I encourage the use of unique_span's: owning, typed, lightweight-ish containers - like a fusion of std::span<T> and std::unique_ptr<T[]> . I wonder if that might seem less annoying to GP. --- [1] : https://github.com/eyalroz/cuda-api-wrappers/ https://github.com/eyalroz/cuda-api-wrappers/
- einpoklum 9mo agoThe title reminds of this: https://youtu.be/TGfQu0bQTKc?si=7TiDRic6LaWI1Xpc&t=70 https://youtu.be/TGfQu0bQTKc?si=7TiDRic6LaWI1Xpc&t=70 "In Rust you need to worry about borrowing. In C++ you don't have to worry about borrowing; in C++ you have to worry about ownership, which is an old concept..." :-P
- jurschreuder 9mo agoI don't know why people use 'new' and 'delete' in all the examples how memory in C++ works because you never normally use them during coding only if you want to make your own container which you might do once to learn about the internals. C++ by default creates objects by value (opposed to any other language) and when the variable goes out of scope the variable is cleaned up. 'new' you use when you want to make a global raw pointer outside of the normal memory system is how I would see it. You really never use it normally at least I don't. A good rule of thumb is not to use 'new'.
- vlovich123 9mo agoAnd yet, I interviewed 10 people easily where I was using new and delete in the example code and only one person asked "hey - can we use unique_ptr?".
- deleted 9mo ago[deleted]
- oxag3n 9mo agoOwnership problems with pointer/references don't end with allocation. A codebase can use only std::make_unique() to allocate heap, and still pass around raw pointers to that memory (std::unique_ptr::get()). The real problem is data model relying on manual lifetime synchronization, e.g. pass raw pointer to my unique_ptr to another thread, because this thread joins that thread before existing and killing the unique_ptr.
- vlovich123 9mo agoI don’t disagree. That’s why I don’t write C++ anymore. It’s a masochistic language and trying to do it in a team environment with people who do understand how to do it properly is a mess let alone adding in people who don’t know.
- mackeye 9mo agomany schools (like mine) don't teach unique pointers in the pure "programming" class sequence, but offer a primer in advanced classes where c++ happens to be used, with the intent to teach manual memory management for a clearer transition to e.g. upper-levels which use c.
- dpsych 9mo agoI think in the `Move` section the delete[] should be delete[] old_buffer; rather than new_buffer;
- cocoto 9mo agoWhy are some examples full of errors? The `set_vec` method for instance does not bind the reference, you can't change the reference itself... so the code would simply copy the vector and there would be no dangling reference... And `B` is missing a constructor since the default constructor would be ill-formed (you can't default initialize a reference). Anyway the article is quite approachable, do not take my criticism to shy away from writing!
- pixelesque 9mo agoYeah, that example's totally wrong, as you say, the std::vector<int> would get copied by value, so there'd be no issue at all.
- tialaramex 9mo agoI strongly encourage people writing textual examples in 2026 to use Compiler Explorer. https://cpp.godbolt.org/ https://cpp.godbolt.org/ Matt Godbolt's tool lets your reader play with your examples and learn more about what's going on. As a bonus, if it doesn't compile and work in Compiler Explorer now you know early before you hit "publish". It's the same reason you should run a spellchecker, raweht thun jstu hope forr th bess
- vqsubu16 9mo agoWhy there is the calling of "read(buffer.get());" in the first example (inside of the 'while' loop)? It is a 'char *buffer' type, unless I'm mistaken raw pointers don't have methods/member functions?
- dundarious 9mo agocopy-paste error given the next example uses a smart ptr type that has a .get() to get the actual pointer.
- fleshmonad 9mo agoAuthor currently unemployed type post to state in zoomerspeech
- Surac 9mo agothis article showes very nice what i do not like in modern c++. Packing easy concepts like lifetime and ownership of data behind complex generic named classes. don't get me wrong; i still like OOP, i even use OOP in c (wel OOP like code) but i do not like the concept of packing easy things in complex ones. perhaps im a litte old :)
- foldr 9mo agoC++ doesn’t really have an ownership system. You can use certain language features to implement certain kinds of ownership discipline, but the language itself doesn’t really have an opinion on who should own what. For example, the article talks about cases where a returned value “must” be deallocated by the calling code, but there is no “must” about it as far as the language is concerned. You’re perfectly at liberty to allocate something without ever freeing it (and this isn’t even a memory leak if the value is needed throughout the lifetime of the program).