D2 の動的配列を少し調べたところ、理解するのが非常に難しいことがわかりました。また、仕様を間違って解釈しているようです..動的配列の参照またはスライスでの作業は、配列を変更するときに非常にエラーが発生しやすいようです...または、基本を理解していないだけですか?
同じ配列を参照すると、実際の項目のみが共有されます。
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);
それらは同じ配列を参照するため、一方を変更すると他方が変更されます。
auto a = [1,2];
auto b = a;
a[1] = 20;
assert(a == [1,20]);
assert(a == b);
配列の仕様から
効率を最大化するために、ランタイムは常に配列のサイズを変更して余分なコピーを回避しようとします。新しいサイズが大きく、配列が new 演算子または以前のサイズ変更操作によって割り当てられていない場合は、常にコピーが実行されます。
したがって、長さを変更しても、必ずしも参照が壊れることはありません。
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]);
配列の仕様から
オペランドの 1 つが長さ 0 の配列であっても、連結は常にそのオペランドのコピーを作成します。
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
しかし、配列が互いにステップする場合、値は新しい場所にコピーされ、参照が壊れます。
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);
変更を行う前に両方の配列の長さを変更すると、上記と同じ結果が得られます (上記を考えると、これが予想されます)。
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);
長さを変更したり、カンカテーションしたりする場合も同じです(上記を考えると、これが予想されます):
auto a = [1];
auto b = a;
b.length = 2;
a ~= 2;
assert(a == [1,2]);
assert(b == [1,0]);
assert(a.ptr != b.ptr);
しかし、スライスも登場し、突然、さらに複雑になります! スライスは孤立している可能性があります...
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]);
だから...同じ動的配列への複数の参照を持つことは悪い習慣ですか? そして、スライスを渡すなど?それとも、D の動的配列のポイント全体を見逃して、ここから抜け出してしまったのでしょうか。