4 ms·
Every one of those problems you mentioned occurred in C code, not C++. That might seem like quibbling, but many of those bugs are caused by C memory management
by thrownaway2424 11y ago
Every one of those problems you mentioned occurred in C code, not C++. That might seem like quibbling, but many of those bugs are caused by C memory management bullshit like malloc(that) if (error) goto: free(that), which isn't a problem that C++ has. A scratch reimplementation of OpenSSL in C++ would probably be 1/3rd the lines of code and entirely devoid of both goto and malloc.
- rvense 11y agoAnd a Rust implementation might be half the code and entirely devoid of classes of bugs that might be in the C++.
- quotemstr 11y agoRust's standard library aborts on OOM. That's completely unacceptable. More generally, I find Rust's error handling awkward --- the most common excuse for Rust's OOM handling is "Otherwise, you'd need to cart Result everywhere." Of course. That's why we invented exceptions decades ago. The designers should have used traditional exceptions instead of trying to create something new --- the designers (just like Go's designers) had to go back and add exception support anyway. I'd have liked Rust more if it'd focused on memory safety and less on being different for the sake of being different. I want a memory safe, non-GC language with traditional curly brace syntax, traditional types, and exceptional error handling. Modern C++ is a much better approximation of that language than Rust is.
- dbaupp 11y agoIt's definitely very important for some domains, but handling OOM "properly" is a really vague/impossible concept for most non-bare-metal programming. Modern operating systems will over-allocate/over-commit memory via virtual memory (so malloc usually succeeds), and kill programs when the physical memory limit is reached, and/or just grind to a halt by swapping. For instance, I can happily "allocate" 100 terabytes of memory on my laptop (16 GB of RAM, 16 of swap): use std::{thread, time}; fn main() { let _v: Vec<Vec<u8>> = (0..100_000) .map(|_| Vec::with_capacity(1 << 30)) // 1GB each .collect(); thread::sleep(time::Duration::from_secs(10)); } Of course, if I actually tried to use much of it, bad things would happen, but the point is the allocations themselves never failed. Bare-metal programming, like a kernel, will typically use the lower-level `core` part of the standard library, rather than the whole thing (i.e. `std`) because the kernel will be literally providing the interfaces required for most of std-minus-core. (I think it would be really great if the standard library could be less harsh when an OOM is actually detected, and I suspect it can be tuned in future, but it's not a show-stopper for most tasks.)
- quotemstr 11y ago> handling OOM "properly" is a really vague/impossible concept for most non-bare-metal programming I strongly disagree. Handling memory allocation failure is trivial: throw an exception. It's also trivial to reserve enough memory to throw an exception. I honestly don't understand people who claim that recovering from OOM is futile because you need to almost always allocate memory to recover: in fact, you almost never do. > Modern operating systems will over-allocate/over-commit memory Windows is a very modern operating system and does not overcommit. (To its credit: overcommit is a terrible idea.) Even on overcommit systems, you can exhaust your address space and see allocation failures. No, 64 bits is not actually infinity. No, the whole world is not 64 bit. (Not every program even benefits from being 64 bit --- that's why the x32 ABI exists.) > point is the allocations themselves never failed. The resource you're allocating is address space. When you run out of this resource, your allocations will fail. On overcommit systems, you don't allocate commit charge until you access the memory. It's very difficult to explain to people who work exclusively on overcommit systems that "memory" isn't a single resource, but a set of related ones, each of which can be exhausted. > I think it would be really great if the standard library could be less harsh when an OOM is actually detected The only reasonable thing to do on OOM failure is throw an exception, like Java and C++ do. Error codes are too cumbersome even if you dress them up and call them "monads" --- a lot of code allocates, so if you used error codes to indicate OOM, you'd have to manually propagate exceptions from almost everywhere) and just panicking or aborting is too brittle, since you can, in fact, successfully recover from allocation failure, persistent folk myths aside. Now Rust has both Result _and_ panic/catch_panic, which I think is both sad and hilarious, as it's going to lead to decades of confusion over which error reporting mechanism to use in a particular situation. (The Go designers made exactly the same mistake, as did the designers of the old java.io.File interface.) It's a shame for such a young language to have that kind of baggage already. If Rust's designers hadn't been so stridently anti-exception in the first place, we'd have ended up with a much better language.
- kibwen 11y ago> Now Rust has both Result _and_ panic/catch_panic The forthcoming facilities for "catching" panics are deliberately hobbled so as to prevent them from being suitable for use as a general-purpose error-handling mechanism. What they're for is fault isolation, most specifically for preventing code from unwinding across a FFI boundary (which would result in undefined behavior).
- Manishearth 11y agoYou're not supposed to use the stdlib for baremetal programming. > instead of trying to create something new monadic error handling isn't new. It's an old feature used by many languages, and preferred by many over exceptions.
- quotemstr 11y ago> You're not supposed to use the stdlib for baremetal programming. I don't think it's useful to partition the world into microcontrollers and "LOL, memory is finite?" domains. Allocations can fail for normal programs, particularly when imposing subsystem-specific allocation limits or when running in small, crowded address spaces (e.g., mobile devices). It's often useful to be able to recover from this condition without completely killing the process, since process death is much more annoying for users than a specific task failing. (Wouldn't you rather see a video not play than see your entire program die?)
- kibwen 11y agoRust's libcore wasn't split out for "LOL, memory is finite" domains. It exists so that you can write Rust programs that restrict themselves to doing no dynamic allocation whatsoever, as needed for environments where an allocator simply isn't available or allowed.
- quotemstr 11y agoMy point is that I want to write programs that do use dynamic allocation, but also handle failure of this dynamic allocation in a reasonable way. Right now, Rust's philosophy is that you can choose whether to use dynamic allocation, but if you do, it'd better be an infallible allocator.
- mondoshawan 11y agoOn OOM, what should happen other than a hard abort? On most VM systems, malloc and friends oversubscribe what is actually available. What possible recovery mechanism can you implement to prevent this from happening?
- quotemstr 11y ago> On OOM, what should happen other than a hard abort? On a web server, 500? On a document editor? "Sorry, couldn't add attachment". What to do in response to error is application-specific. My point is that memory is not special and there is no reason to treat memory errors differently from other errors. You wouldn't abort if you run out of disk space. > On most VM systems, malloc and friends oversubscribe what is actually available. Windows is a common non-overcommit OS. Even on overcommit systems, it's possible to exhaust a process's virtual address space. (Overcommit systems also have ulimit -v.) If you do run out of either address space or commit, it's frequently the case that you can just stop what you were doing and display an out-of-memory dialog. The process of "stop what you were doing" can certainly free enough memory to keep going.
- mondoshawan 11y agohttp://www.gotw.ca/publications/mill16.htm http://www.gotw.ca/publications/mill16.htm So Herb Sutter mostly agrees with your view, but my question is a corollary, and something he touches on: how do you keep going if you stop what you were doing? The process of recovering is not straightforward, and if you have threads running, that process is utter chaos, if not outright impossible in some languages. Even on non overcommit systems, the user finding another way to work around a memory failure is useless because the system is already hosed to the point where a small memory allocation will fail. Either way, the situation is so bad that the user does not have the ability to recover what was just done in your application without closing your application in the first place -- which, incidentally, leaves the user stuck in exactly the same place as if your application aborted. The big idea here is that the OOM condition may not be because of your application.
- 11y ago
- sampo 11y ago> Every one of those problems you mentioned occurred in C code, not C++ The title of the post talks about C, not C++.
- adrianN 11y agoWhile C++ certainly makes it easier to write safe code, you still need to be quite careful. C arrays, manual memory management, dangling pointers and all kinds of other unsafe constructs lurk behind the thin veneer of modern C++ style.
- jernfrost 11y agoNo way, C++ removed some C problems but just added a whole host of its own problems, that don't exist in C: operator overload hell, static initialization and deinitialization hell. Calling virtual methods in constructors blow up. I programmed C++ for 13 years and must have had rose tinted glasses on. I kept reading books like Effective C++ thinking that my bugs would go away as soon as I learned all the intricacies of C++ and best practices. I realize now that I mostly program in other languages that the enormous amount of knowledge you need when writing C++ safely simply isn't needed in most other mainstream languages. If you think C++ is the answer to C's problems I think you suffer Stockholm syndrome. You've gotten so used to all the issues in C++ and started thinking about them as normal, so you stop seeing what a mess this language is.
- thrownaway2424 11y agoNobody is going to make you overload operators, do work in constructors, or throw exceptions. Restrict yourself to the subset of C++ that you prefer. By comparison there is no subset of C that lacks malloc/free.
- sixbrx 11y agoIn practice most of us are restricted to the subsets (note plural) chosen by the people who wrote the original systems we work on.
- ant6n 11y agoBut then you can't move to another language anyway. If you can move to another language (say if you start a new project), it's worth moving from C++ to C++11.