d的两种初化方式不一样
struct A
{
int[] i;
}
struct B
{
A[] a = [A.init];
}
A和B如上,代码:
auto b1 = B.init;
b1.a[0].i ~= 1;
b1.a ~= A.init;
b1.a[0].i ~= 11;
b1.a[1].i ~= 12;
b1.writeln;
auto b2 = B();
b2.writeln;
//期望相同
B([A([1, 11]), A([12])])
B([A([])])
期望编译.但代码:
B b1; // auto b1 = B.init;
b1.a[0].i ~= 1;
b1.a ~= A.init;
b1.a[0].i ~= 11;
b1.a[1].i ~= 12;
b1.writeln;
B b2; // auto b2 = B();
b2.writeln;
//没有打印期望的
B([A([1, 11]), A([12])])
B([A([1])])
为什么?
A[] a = [A.init];
问题在此,它是引用在B的所有副本中共享的静态数组实例.几乎肯定你不想要它.
B.a[0]是跨不同默认构造的所有B的*相同对象*.
不要这样.只有基本值和不变串才这样初化.用数组或类对象,可能得到共享.
如果在构造器(需要个参数)或工厂函数中初化,会获得更加一致行为,因为每个实例都有自己的数组.
至于为什么B()和B.init在此不同,我不知道,可能是编译器的一些微妙实现.
我最近实验:
struct Xml {
string beg;
string end = "/>"; // 所有实例共享
// 无分配.
// ...
}
这不是错误:
void main()
{
struct B
{
struct A
{
int i = 10;
}
A[] a = [A.init];
}
B[2] b;
assert(b[0].a.ptr is b[1].a.ptr);
}
这不是错误.他们指向内存中A的完全相同实例:
这里是:编译时分配了单个全局的在所有B.init实例之间共享的A[].就像如下:
struct B
{
struct A
{
int i = 10;
}
static A[] globalArray = [A.init];
A[] a = globalArray;
}
我想调整默认构造器,但构不能有自定义版.
添加带参构造器,似乎是个侵改.
有静态opCall,也像侵改.
import std.stdio;
struct A
{
int[] i;
}
struct B
{
A[] a = [A.init];
static B opCall()
{//
return B.init;
}
}
void main()
{
auto b1 = B.init;
b1.writeln;
B b2 = B();
b2.writeln;
B b3;
b3.writeln;
}
静态数组是值类型.复制静态数组时,副本数据存储在与原始数组不同的内存块中:
int[1] a = [1];
int[1] b = a;
assert(&a[0] !is &b[0]);
//内存不同
动态数组是引用类型.复制动态数组时,两个副本都指向同一个内存块:
int[] a = [1];
int[] b = a;
assert(&a[0] is &b[0]);
为创建有自己内存块的与原始数组分开的动态数组副本,必须使用内置.dup方法:
int[] a = [1];
int[] b = a.dup;
assert(&a[0] !is &b[0]);
//不同内存
浙公网安备 33010602011771号