Struct 使用单个引用传递结构是否有任何隐藏成本?

Struct 使用单个引用传递结构是否有任何隐藏成本?,struct,d,Struct,D,我最近读了一篇关于D中的结构和类的文章,有一次作者评论说 …这是结构的完美候选者。原因是它只包含一个成员,一个指向ALLEGRO_配置的指针。这意味着我可以毫无顾忌地按值传递它,因为它只有指针的大小 这让我思考;真的是这样吗?我可以想到一些情况,在这些情况下,相信你正在“免费”传递一个结构可能会有一些隐藏的陷阱 考虑以下代码: struct S { int* pointer; } void doStuff(S ptrStruct) { // Some code here }

我最近读了一篇关于D中的结构和类的文章,有一次作者评论说

…这是结构的完美候选者。原因是它只包含一个成员,一个指向ALLEGRO_配置的指针。这意味着我可以毫无顾忌地按值传递它,因为它只有指针的大小

这让我思考;真的是这样吗?我可以想到一些情况,在这些情况下,相信你正在“免费”传递一个结构可能会有一些隐藏的陷阱

考虑以下代码:

struct S
{
    int* pointer;
}

void doStuff(S ptrStruct)
{
    // Some code here
}

int n = 123;
auto s = S(&n);
doStuff(s);
当s被传递到doStuff()时,单指针(包装在结构中)真的就是传递给函数的全部内容吗?在我看来,任何指向成员函数的指针以及结构的类型信息都会被传递

当然,这对类来说不是问题,因为它们总是引用类型,但结构的传递值语义向我建议,任何额外的“隐藏”数据(如上文所述)都将与结构指向int的指针一起传递给函数。这可能会导致程序员认为它们传递的是(假设是64位机器)8字节指针,当它们实际传递一个8字节指针时,加上其他几个指向函数的8字节指针,再加上对象的typeinfo的字节数。粗心的程序员在堆栈上分配的数据远远超出了预期


我是在这里追逐阴影,还是在传递带有单个引用的结构时,这是一个合理的问题,并且认为您得到的是一个伪引用类型的结构?D中是否有某种机制可以防止这种情况发生?

没有传递隐藏数据。
结构
完全由声明的内容组成在其中(以及任何填充字节,如果需要),没有其他内容。不需要传递类型信息和成员函数信息,因为它们都是静态的。由于
结构
无法从另一个
结构
继承,因此不存在多态性。

我认为这个问题可以推广到包装本机类型。例如,您可以创建一个SafeInt类型来包装cts类似于int,但会引发任何整数溢出条件

这里有两个问题:

  • 编译器可能不会像使用本机类型那样优化代码

    例如,如果要包装int,可能会实现重载算术运算符。足够智能的编译器将内联这些方法,生成的代码与int没有什么不同。在您的示例中,哑编译器可能会以某种笨拙的方式编译解引用(例如,获取结构的起始地址,添加指针字段的偏移量(即0),然后取消引用该字段)

    此外,调用函数时,编译器可能会决定以其他方式传递结构(例如,由于优化效果不佳或ABI限制)。如果编译器不注意结构的大小,并且以相同的方式处理所有结构,则可能会发生这种情况

  • 如果在函数中声明,D中的
    struct
    类型可能确实有一个隐藏成员

    例如,以下代码起作用:

    import std.stdio;
    
    void main()
    {
        string str = "I am on the stack of main()";
    
        struct S
        {
            string toString() const { return str; }
        }
    
        S s;
        writeln(s);
    }
    
    它之所以有效,是因为S保存了指向main()堆栈帧的隐藏指针。您可以通过在声明前加上
    static
    (例如
    static struct S
    )来强制结构没有任何隐藏指针


  • 你能解释一下你所说的静态是什么意思吗?当你说静态时,我认为静态结构是最字面意义上的,就像在程序运行期间内存中存在的一样。为什么结构是“静态的”这一事实意味着不需要传递typeinfo和成员函数指针(运行时)类型和成员访问都可以在编译时完全确定。
    由于一个结构不能从另一个结构继承,因此不存在多态性
    -因此结构没有虚拟函数,因此不需要在每个实例中包含方法指针表。类似地,缺少结构子类化意味着编译-结构变量的时间类型与它的运行时类型总是相同的,所以不需要Type信息。我甚至不考虑编译器优化和嵌套结构;这是一些好的地方。您还可以解决我在关于结构的Type信息和指针到成员函数的问题中提出的问题吗?静态(信息在编译器的内存中),并且不是每个结构实例的一部分。添加任意数量的方法都不会增加结构实例。D中的结构没有RTTI,因此typeinfo也不是隐藏成员。嵌套结构的优点是,我忘记了解决这个问题。我要补充的是,当前的编译器不太可能处理包含int的结构(例如)与int不同。我不太确定“注意结构大小”这件事……不这样做实际上会违反系统ABI,因为ABI要求以不同的方式传递不同大小的结构(例如,在SystemV x86-64 ABI中,大小小于16的结构在寄存器中传递,而较大的结构在堆栈中传递)。当然,但我认为我们不能代表所有的ABI。