RCArray is unsafe
Nick Treleaven via Digitalmars-d
digitalmars-d at puremagic.com
Mon Mar 9 07:46:42 PDT 2015
On 04/03/2015 08:55, Ivan Timokhin wrote:
> void main()
> {
> auto arr = RCArray!int([0]);
> foo(arr, arr[0]);
> }
>
> void foo(ref RCArray!int arr, ref int val)
> {
> {
> auto copy = arr; //arr's (and copy's) reference counts are both 2
> arr = RCArray!int([]); // There is another owner, so arr
> // forgets about the old payload
> } // Last owner of the array ('copy') gets destroyed and happily
> // frees the payload.
> val = 3; // Oops.
> }
We could prevent reassignment of arr while val is alive, but perhaps
still allow mutation of existing elements through arr.
I've changed Marc Schütz's example to explore this:
void main() {
auto a = RCArray!int([5]); // a's refcount is now 1
foo(a, a[0]); // pass by ref
}
void foo(ref RCArray!int a, ref int t) {
a[0] = 4; // ok
a = RCArray!int([]); // drop the old a
t = 3; // oops, t is gone
}
I think Rust would enforce that either a *or* t can be mutably borrowed
at once (and for a, t can't even be immutably-borrowed). Without
designing a system, in theory foo is OK if a is const, but that prevents
a[0] = 4. This could be allowed as long as a is not reassigned (i.e. a
is head-const).
To support RCDynamicArray that supports appending and resizing, these
operations also need to be excluded, whilst potentially allowing
existing elements to be mutated.
(I've seen Andrei's solution for the above example, but it doesn't work
for Ivan Timokhin's code, and for the former it can be non-ideal).
Perhaps a parameter attribute similar to head-const (but somehow
configurable by the container author) could enforce this. The author of
foo would need to use this attribute for a. The container could mark the
safe mutation operations with this attribute.
Just an idea. I haven't considered other types of container, maybe it
would help those also.
More information about the Digitalmars-d
mailing list