Herb Sutter on increasing safety in C++
Herb Sutter on increasing safety in C++
Posted Mar 14, 2024 1:39 UTC (Thu) by NYKevin (subscriber, #129325)In reply to: Herb Sutter on increasing safety in C++ by dvrabel
Parent article: Herb Sutter on increasing safety in C++
This is an unreasonable expectation. Arc::into_inner() is a highly specialized interface. It is not designed for general use. It *should* be hard to use correctly.
Before I explain how this interface should be used, we need to take a step back and talk about the actual problem that it is trying to solve. You have an object behind an Arc; let's say it's Arc<Foo> (for some type Foo). There are several different reasons you might plausibly want to use this function:
* You want to mutate the Foo instance. Then call Arc::get_mut().
* You want to dispose of something owned by the Foo when the refcount drops to zero. Then implement Drop for Foo, and write the code in its drop() method.
* You want to replace the Foo instance with a different Foo instance. Then call mem::replace() or mem::swap() on the &mut Foo that you can get out of get_mut().
* You want to do one of the above, even if another thread might be using the Foo instance. Then wrap the Foo in a sync::Mutex or sync::RwLock.
* You want to take the Foo object out of the Arc and consume it. Then use an Arc<Option<Foo>> (plus a lock, if desired) and call Option::take().
All of the above are straightforward to use correctly and have no problems with silently doing the wrong thing. Here is the actual use case for Arc::into_inner():
* You want to take the Foo object out of the Arc and consume it, you don't want to do that until it is no longer in use, you don't want to write code for the case where the Foo has already been consumed, the code that consumes the Foo can't feasibly live in Drop::drop(), *and* you know that all clones of the Arc are owned by worker objects or worker threads, which all know how to consume the Foo at the end. Then all you have to do is ensure that every function which takes an owned Arc<Foo> either consumes it with into_inner() or passes it along to another part of the worker logic, and that it is never permanently stored in some long-lived data structure. And yes, that is difficult, but as mentioned, all of the simple use cases already have another solution which is easier to use and just as performant (or nearly so).
Posted Mar 14, 2024 10:12 UTC (Thu)
by dvrabel (subscriber, #9500)
[Link] (1 responses)
If I have a T I can get a &mut T only if the compiler can prove that it is safe to do so.
If I have a Arc<T> I can only get a &mut T if the runtime check of the reference count says it is safe.
Posted Mar 14, 2024 16:59 UTC (Thu)
by NYKevin (subscriber, #129325)
[Link]
Herb Sutter on increasing safety in C++
Herb Sutter on increasing safety in C++
