Miré un poco las matrices dinámicas en D2, y las encontré muy difíciles de entender. También parece que estoy interpretando la especificación erróneamente ... Trabajar en una referencia o porción de una matriz dinámica parece muy propenso a errores cuando se cambian las matrices ... ¿O simplemente no entiendo los fundamentos?¿Es una mala práctica alterar las matrices dinámicas que tienen referencias sobre ellas?
Refiriéndose a la misma matriz sólo comparte los artículos reales:
auto a = [1];
auto b = a;
assert(&a != &b); // different instance; Doesn't share length
assert(a.ptr == b.ptr); // same items
assert(a == [1]);
assert(a == b);
Como hacen referencia a la misma matriz, el cambio de uno cambia el otro:
auto a = [1,2];
auto b = a;
a[1] = 20;
assert(a == [1,20]);
assert(a == b);
De la especificación en la matriz de
Para maximizar la eficiencia, el tiempo de ejecución siempre intenta cambiar el tamaño de la matriz para evitar extra copiando Siempre hará una copia si el nuevo tamaño es más grande y la matriz no fue asignada a través del operador nuevo o una operación de cambio de tamaño anterior .
Así cambiando la longitud no se rompe neccesarily la referencia:
auto a = [1];
auto b = a;
b.length = 2;
assert(b == [1,0]);
assert(a == [1]); // a unchanged even if it refers to the same instance
assert(a.ptr == b.ptr); // but still the same instance
// So updates to one works on the other
a[0] = 10;
assert(a == [10]);
assert(b == [10,0]);
De la especificación en la matriz de
concatenación siempre crea una copia de sus operandos, incluso si una de las operandos es un conjunto 0 longitud
auto a = [1];
auto b = a;
b ~= 2; // Should make a copy, right..?
assert(a == [1]);
assert(b == [1,2]);
assert(a != b);
assert(a4.ptr == b.ptr); // But it's still the same instance
a[0] = 10;
assert(b == [10,2]); // So changes to a changes b
Pero cuando las matrices se paso el uno del otro, los valores se copian a una nueva ubicación y la referencia roto:
auto a = [1];
auto b = a;
b ~= 2;
assert(a == [1]);
assert(b == [1,2]);
a.length = 2; // Copies values to new memory location to not overwrite b's changes
assert(a.ptr != b.ptr);
Cambio de la longitud de ambas matrices antes de hacer un cambio da el mismo resultado que el anterior (que se lo esperar que esto da la anterior):
auto a = [1];
auto b = a;
a.length = 2;
b.length = 2;
a[1] = 2;
assert(a == [1,2]);
assert(b == [1,0]);
assert(a.ptr != b.ptr);
Y la misma longitud o al cambiar cancatenating (I esperaría que este le dio el anterior):
auto a = [1];
auto b = a;
b.length = 2;
a ~= 2;
assert(a == [1,2]);
assert(b == [1,0]);
assert(a.ptr != b.ptr);
Pero luego las rebanadas también entran en escena, ¡y de repente es aún más complicado! Las rebanadas podrían quedar huérfanos ...
auto a = [1,2,3];
auto b = a;
auto slice = a[1..$]; // [2,3];
slice[0] = 20;
assert(a == [1,20,3]);
assert(a == b);
a.length = 4;
assert(a == [1,20,3,0]);
slice[0] = 200;
assert(b == [1,200,3]); // the reference to b is still valid.
assert(a == [1, 20, 3, 0]); // but the reference to a is now invalid..
b ~= 4;
// Now both references is invalid and the slice is orphan...
// What does the slice modify?
assert(a.ptr != b.ptr);
slice[0] = 2000;
assert(slice == [2000,3]);
assert(a == [1,20,3,0]);
assert(b == [1,200,3,4]);
Así que ... ¿Es una mala práctica de tener múltiples referencias a la misma matriz dinámica? ¿Y pasando rodajas, etc.? ¿O estoy fuera de aquí, perdiendo todo el punto de las matrices dinámicas en D?
Gracias por una respuesta buena y detallada. También escuché acerca de la propiedad .capacity que dice la longitud máxima que la matriz puede tener antes de que necesite una reasignación. Al hacer "auto b = a" obtienen una referencia diferente; & a! = & b, pero parece que "es" usa .ptr bajo el capó para verificar la igualdad referencial. – simendsjo