【发布时间】:2016-04-27 20:45:40
【问题描述】:
我对 D 语言产生了兴趣并开始学习它,因为印象中它可以支持比 C 或 C++ 更简单和更高效的编码,同时保留使用用这些其他语言编写的代码的能力。
但是,在尝试构建一个二维数组时,我观察到了这一点:
auto a = new double[][](1000,3); // clean and seemingly elegant
a.length = 0; // To fill the array by ~= operator
a ~= [1, 2, 3]; // fill the first row
writeln(a); // -> [[1, 2, 3]] (OK)
writeln(a.capacity,a[0].capacity); // -> 1 3 (should be 1000 3)
感觉已经不对了,因为我明确表示希望为 1000x3 的数字保留内存。尽管如此,Digital Mars D 和 GCC gdc 编译器都会产生相同的结果。
所以为了使数组真正是二维的,我添加了另一行。
a ~= [3, 4, 5]; // add another row
writeln(a); // -> [[1, 2, 3], [4, 5, 6]] (OK)
writeln(a.capacity,a[0].capacity); // -> 3 3
如果这意味着a 的内容占用了3*3*double.sizeof 大小和行优先布局的实心内存块,这是可以接受的。但是更多的惊喜正在发生——当我想从 C 的角度检查这个数组的布局时:
double* p = &(a[0][0]); // get a C-like pointer to the data
for(size_t i=0; i<20; i++) {
writef("%.0f ", *(p+i)); // should be: 1 2 3 4 5 6 nan nan ...
}
writeln();
我得到了令人费解的结果,并且在编译器之间有所不同。 dmd with libphobos2 (version 2.071.0) 说:
1 2 3 0 0 0 0 0 4 5 6 0 0 0 0 0 0 0 0 0
但使用 gdc(GCC 版本 4.8.4)相同的代码会打印:
1 2 3 0 nan nan nan 0 nan nan nan 0 nan nan nan 0 nan nan nan 0
哎呀。这既不可用也不便携。要么数组根本不连续(所以我读了一些其他内存),或者两个实现都有错误,因为应该保证使用nan 进行初始化。好的,我已经知道我可以使用 malloc 并像在 C 中那样做所有事情,但是我看不到学习另一种巨大的野兽的优势,这种语言有自己的古怪技巧。
有没有一种简洁的方法可以用 C 布局制作连续的多维数组,同时又不会失去 D 的优势,如内存管理、范围、切片、算法等?
编辑:
在@weltensturm 的回答之后,我修复了我的错误并进行了更多测试。我实际上需要一个动态数组,因为我从 FIFO 中读取了数字,但我不知道先验需要多少行。这段代码显然有效:
auto as = new double[3][0]; // Inconsistent w/C: this is 0 rows by 3 columns
auto ad = new double[][](0,3); // also 0 x 3
as ~= [1,2,3]; as ~= [4,5,6];
ad ~= [1,2,3]; ad ~= [4,5,6]; // I can append to both
writeln(as); // -> [[1, 2, 3], [4, 5, 6]]
writeln(ad); // -> [[1, 2, 3], [4, 5, 6]]
writefln("as capacity: %dx%d", as.capacity, as[0].capacity);
// -> as capacity: 2x0
writefln("ad capacity: %dx%d", ad.capacity, ad[0].capacity);
// -> ad capacity: 3x3
double* p = &(as[0][0]);
for(size_t i=0; i<6; i++) writef("%.0f ", *(p+i)); // -> 1 2 3 4 5 6
writeln();
p = &(ad[0][0]);
for(size_t i=0; i<9; i++) writef("%.0f ", *(p+i)); // -> 1 2 3 4 5 6 0 0 0
writeln();
as 和 ad 实际上都是动态的,并且在追加时会调整大小,但它们的行为确实不同 - 查看追加后的容量。
所以现在的问题是,我可以依赖任何这些替代方案的行为吗?至少对于new double[3][0] 语法,它是否由语言保证?是否可以保证“动态”(new double[][](0,3)) 数组的布局和连续性,只要我知道 不 做什么(例如不直接更改 length 属性)?
【问题讨论】:
-
你有一个动态数组的动态数组。您会获得连续的内存占用,需要使内部维度保持静态。
标签: c multidimensional-array interface d