【发布时间】:2011-03-25 21:42:39
【问题描述】:
我看了一点 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);
来自数组规范
为了最大限度地提高效率,运行时总是尝试调整 数组到位以避免额外的复制。它总是会做一个副本 如果新的大小更大并且数组不是通过 新操作员或以前的操作员 调整大小操作。
因此更改长度不一定会破坏参考:
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]);
来自数组规范
连接总是会创建其操作数的副本,即使其中一个操作数是长度为 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 中动态数组的全部意义?
【问题讨论】: