[英]Are There Any Hidden Costs to Passing Around a Struct With a Single Reference?
我最近在阅读关于D中的结构和类的这篇文章,并且作者一度评论说
...这是结构的完美候选者。 原因是它只包含一个成员,一个指向ALLEGRO_CONFIG的指针。 这意味着我可以无需小心地传递值,因为它只是指针的大小。
这让我思考; 真的是这样吗? 我可以想到一些情况,其中相信你正在“免费”传递一个结构可能会有一些隐藏的陷阱。
请考虑以下代码:
struct S
{
int* pointer;
}
void doStuff(S ptrStruct)
{
// Some code here
}
int n = 123;
auto s = S(&n);
doStuff(s);
当s传递给doStuff()时,是否有一个指针(包含在结构中) 真正传递给函数的所有东西? 在我的脑海中,似乎也会传递任何指向成员函数的指针,以及结构的类型信息。
当然,这不是类的问题,因为它们总是引用类型,但是结构的值语义传递向我表明,如上所述的任何额外的“隐藏”数据将被传递给函数以及struct的指针指向int。 这可能导致程序员认为他们正在绕过一个(假设一个64位机器)8字节指针,当他们实际传递一个8字节指针,加上其他几个8字节指向函数时,加上对象的typeinfo是多少字节。 然后,粗心的程序员在堆栈上分配的数据远远超过预期。
我在这里追逐阴影,或者在传递带有单个引用的结构时这是一个有效的问题,并认为你得到的结构是伪引用类型? D中是否有一些机制可以防止这种情况发生?
我认为这个问题可以推广到包装原生类型。 例如,您可以创建一个SafeInt类型,它包装并像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
)。
没有传递隐藏数据。 struct
完全由它中声明的内容(以及必要时的任何填充字节)组成,没有别的。 不需要传递类型信息和成员函数信息,因为它们都是静态的 。 由于struct
不能从另一个struct
继承,因此没有多态。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.