gpt4 book ai didi

arrays - 更改具有对它们的引用的动态数组是不好的做法吗?

转载 作者:行者123 更新时间:2023-12-04 06:27:57 25 4
gpt4 key购买 nike

我查看了 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);

从阵列规范

To maximize efficiency, the runtime always tries to resize the array in place to avoid extra copying. It will always do a copy if the new size is larger and the array was not allocated via the new operator or a previous resize operation.



所以改变长度并不一定会破坏引用:
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]);

从阵列规范

Concatenation always creates a copy of its operands, even if one of the operands is a 0 length array


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 中动态数组的全部内容?

最佳答案

总的来说,你似乎对事情的理解还算不错,但你似乎误解了ptr的目的。属性(property)。它不指示两个数组是否引用同一个实例。它的作用是让您找到指向下面有效的 C 数组的指针。 D 中的数组有它的 length作为它的一部分,所以它更像是一个具有长度和指向 C 数组的指针的结构,而不是像 C 数组。 ptr允许您获取 C 数组并将其传递给 C 或 C++ 代码。您可能不应该将它用于纯 D 代码中的任何内容。如果要测试两个数组变量是否指向同一个实例,则使用 is运算符(或 !is 以检查它们是否是不同的实例):

assert(a is b);   //checks that they're the same instance
assert(a !is b); //checks that they're *not* the same instance

所有这些 ptr两个数组相等表示它们的第一个元素在内存中的相同位置。特别是他们的 length s 可能不同。但是,这确实意味着如果您在其中一个数组中更改它们,则两个数组中的任何重叠元素都会被更改。

当更改 length对于数组,D 尝试避免重新分配,但它可以决定重新分配,因此您不一定依赖于它是否会重新分配。例如,如果不这样做,它将重新分配另一个数组的内存(包括那些与 ptr 具有相同值的内存)。如果没有足够的内存来调整自身的大小,它也可以重新分配。基本上,如果不这样做,它将重新分配另一个数组的内存,否则它可能会或可能不会重新分配。因此,在设置 length 时依赖数组是否会重新分配通常不是一个好主意。 .

我本来希望附加总是按照文档进行复制,但是根据您的测试,它的行为似乎确实像 length确实(我不知道这是否意味着需要更新文档还是它是一个错误 - 我的猜测是需要更新文档)。在任何一种情况下,您当然都不能依赖对该数组的其他引用来在追加后仍然引用同一个数组。

至于切片,它们按预期工作,并且在 D 中被大量使用——尤其是在标准库 Phobos 中。切片是数组的范围,范围是 Phobos 的核心概念。但是,就像许多其他范围一样,更改范围/切片所在的容器可能会使该范围/切片无效。这就是为什么当您使用可以在 Phobos 中调整容器大小的函数时,如果您不想冒险使您必须的范围无效,则需要使用带有 stable 的函数(例如 stableRemove()stableInsert() )容器。

此外,切片是一个数组,就像它指向的数组一样。所以,很自然地,改变它的 length或附加到它会遵循与更改 length 相同的所有规则。属于或附加到任何其他数组,因此它可以重新分配并且不再是另一个数组的切片。

几乎,您只需要注意更改 length以任何方式对数组进行重新分配都可能导致重新分配,因此如果您希望引用继续引用同一个数组实例,则需要避免这样做。如果你绝对需要确保它们没有指向同一个引用,那么你需要使用 dup获取数组的新副本。如果你不惹 length一个数组,然后数组引用(无论是切片还是对整个数组的引用)将继续愉快地引用同一个数组。

编辑:事实证明,文档需要更新。如果可以的话,任何可以调整数组大小的东西都会尝试就地进行(因此它可能不会重新分配),但如果必须这样做,则会重新分配以避免踩踏另一个数组的内存或如果它没有足够的空间重新分配到位。因此,通过设置 length 来调整数组大小应该没有任何区别。属性并通过附加到它来调整它的大小。

附录:任何使用 D 的人都应该阅读 this article在数组和切片上。它很好地解释了它们,并且应该让您更好地了解数组在 D 中的工作原理。

关于arrays - 更改具有对它们的引用的动态数组是不好的做法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3416657/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com