代码之家  ›  专栏  ›  技术社区  ›  minerals

为什么box smallbox=scoped!box();d中有错误吗?

d
  •  0
  • minerals  · 技术社区  · 5 年前

    在“编程在D”书中 destroy and scoped “作者写道,在使用 范围的 如果在左边指定了实际的类类型,就会引入一个bug。

    Box c = scoped!Box();
    

    在该定义中,c不是代理对象;而是程序员定义的引用封装对象的类变量。不幸的是,在右侧构造的代理对象在构造它的表达式的末尾终止。因此,在程序中使用c将是一个错误,可能会导致运行时错误。

    如此

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

    我的解释有点高,因为 auto smallBox 不同于 Box smallBox 除了编译器将推断类型之外?显式类型规范和d编译器推断之间有什么不同 范围的 提前终止对象的代理结构?

    0 回复  |  直到 5 年前
        1
  •  4
  •   Adam D. Ruppe    5 年前

    一般来说,编译器会尝试转换右边的类型,以匹配声明左边的类型。两边都有一个特定的类型——左边实际上不会影响右边的代码成为不同的类型——只是它会转换。编译器将尽可能少地进行转换以匹配左边,如果不可能,则会发出错误。

    auto a = x;
    

    在这里, auto 没有限制,所以 a 与类型相同 x ,因此不需要转换。这是类型推断的最基本情况。

    const a = x;
    

    这里,左手边是 const ,但其他方面是不受限制的。因此,编译器将尝试将x的类型转换为 康斯特 没有进一步的改变。这是稍微复杂一点的类型推断,但仍然非常简单。

    Box a = x;
    

    但在这里,左手边是专门打出来的 Box . 所以不管怎样 X 是,编译器将尝试转换它 明确地 盒子 . 这可能需要各种用户定义的转换,如 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 在那里, 隐式转换为 int . 这是允许的,所以没有错误,但是 Z 现在不同了。对于基类和接口,您可以看到类似的情况:

    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
    

    byte , int ,对于类,这基本上可以按预期工作。字节和int基本上是一样的,类保留一个运行时类型标记来记住它们到底是谁。

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

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

    那个结构 B 现在可以隐式转换为类型 A …但它只是返回一个单独的成员( )而剩下的 在后面。

    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
    }
    

    将此命名为 幻线允许它转换回类类型…但它只返回一个引用成员,而放弃 Scoped ,根据scoped用途的定义,这意味着它消失了,并在进程中破坏了类的内存。这样就留下了一个对已销毁对象的引用,这就是他们警告的bug。