为什么 Box smallBox = scoped!Box();是BUG在D?

Why Box smallBox = scoped!Box(); is a BUG in D?

在 "Programming in D" 书的“destroy and scoped”一章中,作者写道,使用 scoped 时应该小心,因为如果指定实际 class 类型在左侧。

Box c = scoped!Box();

In that definition, c is not the proxy object; rather, as defined by the programmer, a class variable referencing the encapsulated object. Unfortunately, the proxy object that is constructed on the right-hand side gets terminated at the end of the expression that constructs it. As a result, using c in the program would be an error, likely causing a runtime error.

这样

Box smallBox = scoped!Box(); // BUG!
auto smallBox = scoped!Box(); // works fine
const smallBox = scoped!Box(); // works fine

给出的解释对我来说有点高级,因为 auto smallBoxBox smallBox 有何不同,除了类型将由编译器推断?显式类型规范和 D 编译器推断它允许 scoped 代理结构提前终止对象之间有什么不同?

一般来说,编译器会尝试将您右边的类型转换为声明中左边的类型。双方已经有一个特定的类型 - 左侧实际上不会影响右侧的代码成为不同的类型 - 只是它会转换。编译器会尝试做尽可能少的转换来匹配左边,如果不可能则报错。

auto a = x;

这里,auto没有限制,所以a的类型和x的类型是一样的,不需要转换。这是类型推断的最基本情况。

const a = x;

此处,左侧为const,其他不受限制。因此,编译器将尝试将 x 的类型转换为 const 而无需进一步更改它。这是稍微复杂的类型推断,但仍然非常简单。

Box a = x;

但在这里,左侧是专门输入的Box。因此,无论 x 是什么,编译器都会尝试将其 具体地 转换为 Box。这可能会在右侧类型中调用各种用户定义的转换,例如 alias this,或者也可能会进行隐式转换。

让我们具体一点:

byte a;
auto x = a; // x is `byte`, just like a
const y = a; // y is now `const(byte)`, applying const to a's type
int z = a; // z is always an int, now a is converted to it.

z 的情况下,a 隐式转换为 int。这是允许的,所以没有错误,但是 za 现在是不同的东西了。您会看到 base 类 和 interfaces:

类似的东西
class A {}
class B : A {}

auto one = new B(); // one is type B
A two = new B(); // two is now of type A, the B object got converted to the base class A

使用 byteint 和 类,这基本上可以按预期工作。字节和整数基本上是一回事,类 保留运行时类型标记以记住它们的真实身份。

但是对于结构,它可能会导致一些信息丢失。

struct A {}
struct B { A a; alias a this; }

该结构 B 现在可以隐式转换为类型 A... 但它通过仅返回一个单独的成员 (a) 而保留 [=] 的其余部分来实现34=]落后.

B b;
A a = b; // the same as `A a = b.a;`, it only keeps that one member in `a`

这就是 scoped 在内部所做的。它看起来像这样:

struct Scoped(Class) {
     Class c;
     alias c this;
     ~this() { destroy(c); } // destructor also destroys child object
}

那条 alias this 魔法线允许它转换回 Class 类型...但是它只返回一个引用成员,同时放弃其余的 Scoped],根据 Scoped 目的的定义,这意味着它消失了并破坏了进程中的 Class' 内存。因此,您留下了对已销毁对象的引用,这是他们警告的错误。