4 ms·
I see RC and GR as two methods of ensuring memory safety: one that extends the life of an object, and one that asserts the object is still alive. They both prot
by verdagon 4y ago
I see RC and GR as two methods of ensuring memory safety: one that extends the life of an object, and one that asserts the object is still alive. They both protect us from vulnerabilities and UB, but with different approaches.
Yep, it was compared to single-threaded RC for fairness.
- dataflow 4y agoRC isn't there to protect you from vulnerabilities though. It's there to let you share ownership. There's some side benefits in that regard, but the latter can't substitute for the former except in cases where the former is unnecessary to begin with. As an analogy, imagine comparing a safety knife, a kitchen knife, and (a safe version of?) an axe with each other, and touting how much lighter/safer/whatever the first one is compared to the others. Of course that's correct, and you can make the comparison, but there isn't (or at least shouldn't be?) a huge market of people out there using an axe in the kitchen who could've just used a knife instead, so it's a weird choice of a market to sell an otherwise-great product to. (And thanks for clarifying the single-threaded aspect.)
- MaulingMonkey 4y ago> It's there to let you share ownership. And ownership - shared or otherwise - is a great way to eliminate the use-after-free bugs that would otherwise be caused by naively attempting to create a non-owning, borrowing reference to something else. It is in fact the primary use of refcounted pointers in many C++ codebases I've worked with - perhaps with a single std::shared_ptr and several std::weak_ptr s, meaning you're not really sharing ownership per se despite the refcounted nature - or perhaps with multiple std::shared_ptr s out of sheer laziness. I've had my share of C++ code reviews dinged for perfectly valid code containing non-owning references, simply because such code could be fragile and prone to use-after-free heisenbugs in the face of refactoring, and my reviewers were right to do so. Things are safer in Rust - you can play fast and loose with storing &str s and rely on the borrow checker to catch your mistakes - but playing fast and loose with storing std::string_view s will lead to slipped release dates as you chase 11th hour heisenbugs. Store a std::string or std::shared_ptr<std::string> instead, even if it's "unnecessary". > there isn't (or at least shouldn't be?) a huge market of people out there using an axe in the kitchen who could've just used a knife instead Some of us are out camping in the wilderness that is C++ gamedev, and want to make kindling. Do I need to pack a whole axe, or would a knife I need for other reasons anyways make do and lighten my backpack? And even if that's a small market, it's still entirely a reasonable market, and for advertizing to that audience - however niche - comparing said tools would be an entirely justifyable approach to selling the product. I also think you underestimate the size of said market.
- masklinn 4y ago> It is in fact the primary use of refcounted pointers in many C++ codebases I've worked with - perhaps with a single std::shared_ptr and several std::weak_ptr s [...] Store a std::string or std::shared_ptr<std::string> instead, even if it's "unnecessary". Uh, I've been wondering at the use case for rc::Weak, that seems like an interesting halfway point if you think borrowing should work but you can't get the compiler to accept it.
- mgaunard 4y agoshared_ptr is just a code smell. There aren't really many good use cases for shared ownership, using it is just a cop-out because you can't design code properly.
- MaulingMonkey 4y agoEven if true, that's overly dismissive and unactionable, especially when several programming languages bake the same reference counting into their most basic reference semantics, as a poor man's half baked non-sweeping garbage collector. Further - find me a programmer who always designs code properly, and you will have found me a liar. One actionable alternative is explicit owner/borrowing smart pointers, which assert if an owner is destroyed while borrowers are pending - which while not eliminating bugs, at least makes them much shallower to debug. I don't have hands on experience with that style - I inherit codebases and their existing coping patterns too often - but I hear good things from those who do. Another actionable alternative is resorting to a proper garbage collector. Or using a proper COM pointer type. Or RIIR. I resort to Rc/Arc in Rust much less than I resort to shared_ptr in C++ (although it still has its niches.) Then again, I used Arc twice just yesterday: https://github.com/MaulingMonkey/rust_http_chat_server/blob/master/src/main.rs https://github.com/MaulingMonkey/rust_http_chat_server/blob/... `Common` (shared between request-handling worker threads) could be made static instead of Arc (although this would eliminate having separate isolated state for, say, different hosts?) Or I could use a scoped thread API that ensures the worker threads are cleaned up before the main thread does, and leave it on the stack instead. The standard library's scoped threads are nightly-only, but there are third party crates - or I could roll my own with `unsafe { ... }`. `Arc<String>` messages (shared between chat history broadcasting threads until every recipient has sent out a reply) could be simply deep copied. Given the small typical message sizes, that might even be cheaper (although with the heap allocs I wouldn't bet on it.) Or a proper thread safe mpmc FIFO container could be used, although none is in the standard library. A 200 LOC monolithic main.rs isn't exactly well designed, but it didn't need to be. That's a cop-out, but I suspect your pull requests won't be forthcoming either ;).