使用局部变量或多次访问结构值 (C++)
Use local variables or access multiple times a struct value ( C++ )
在 JS 中,创建变量以供重用而不是访问深层对象结构中的值是一个好习惯:
for (var i = 0, l = arr.length; i < l; ++i) {
var someValueINeedOftenHere = arr[i].path.to.value;
// do several things with this var..
}
所以我们不是在这个深层对象结构中寻找值,而是将它存储在本地,我们可以一遍又一遍地重用它。这应该是一个很好的做法,不仅因为它可以让您编写更清晰的代码,还因为性能。
因此,当我编写 C++ 代码时,我必须遍历一个包含大量结构/对象的向量。那么是一样的,还是无所谓的?
一般而言,在 C/C++ 中无所谓。在 C 和 C++ 中,每个结构的内存布局在编译时都是已知的。当您键入 arr[i].path.to.value
时,它基本上与 *(&arr[0] + i * (something) + offset_1 + offset_2 + offset_3)
相同,并且所有这些都将在编译时简化为 *(&arr[0] + i * (something) + something)
之类的东西。而那些 something
将由编译器计算并硬编码到二进制文件中,因此有效地查找 arr[i].path.to
并不比 arr[i].path.to.value
.
快
据我所知,这不是标准或任何东西强制要求的,但这是大多数编译器实际工作的方式。
如果你想在某些特定情况下确定,你可以查看 godbolt 并查看它编写的程序集:http://gcc.godbolt.org/
请注意,我假设当您创建局部变量时,您正在引用值 arr[i].path.to.value
,这与您在 javascript 中所做的最相似。如果您实际上将该值复制到一个新变量,那么这将产生一些复制开销。我不认为复制它会有好处 w.r.t。缓存未命中,除非使用模式非常复杂。一旦你访问 arr[i].path.to.value
一次,它周围的所有东西都会在缓存中,并且没有理由将它复制到堆栈上会使任何事情变得更快。
arr
的none、arr[i]
、path
、to
、value
、[=36=都没有关系] references/pointers,如.
但是,如果 arr
、arr[i]
、path
、to
、value
is/involves a reference/pointer然后访问它们可能是缓存未命中。多次访问它们会导致多次缓存未命中(可能)。
因此,将 reference/pointer 直接存储到 value
可能比在追逐指针到达 value
时获取多个缓存未命中更有效。请记住,编译器可能无论如何都会优化这样的事情。
如果避免缓存未命中,将 value
存储为副本可能会更有效,并且复制起来相对轻松,并且您不需要修改原始值。同样,编译器很可能也会优化这些情况,如果这样做显然会提高性能的话。
这一切都取决于。 仅在证明存在问题时才进行优化。
在 JS 中,创建变量以供重用而不是访问深层对象结构中的值是一个好习惯:
for (var i = 0, l = arr.length; i < l; ++i) {
var someValueINeedOftenHere = arr[i].path.to.value;
// do several things with this var..
}
所以我们不是在这个深层对象结构中寻找值,而是将它存储在本地,我们可以一遍又一遍地重用它。这应该是一个很好的做法,不仅因为它可以让您编写更清晰的代码,还因为性能。
因此,当我编写 C++ 代码时,我必须遍历一个包含大量结构/对象的向量。那么是一样的,还是无所谓的?
一般而言,在 C/C++ 中无所谓。在 C 和 C++ 中,每个结构的内存布局在编译时都是已知的。当您键入 arr[i].path.to.value
时,它基本上与 *(&arr[0] + i * (something) + offset_1 + offset_2 + offset_3)
相同,并且所有这些都将在编译时简化为 *(&arr[0] + i * (something) + something)
之类的东西。而那些 something
将由编译器计算并硬编码到二进制文件中,因此有效地查找 arr[i].path.to
并不比 arr[i].path.to.value
.
据我所知,这不是标准或任何东西强制要求的,但这是大多数编译器实际工作的方式。
如果你想在某些特定情况下确定,你可以查看 godbolt 并查看它编写的程序集:http://gcc.godbolt.org/
请注意,我假设当您创建局部变量时,您正在引用值 arr[i].path.to.value
,这与您在 javascript 中所做的最相似。如果您实际上将该值复制到一个新变量,那么这将产生一些复制开销。我不认为复制它会有好处 w.r.t。缓存未命中,除非使用模式非常复杂。一旦你访问 arr[i].path.to.value
一次,它周围的所有东西都会在缓存中,并且没有理由将它复制到堆栈上会使任何事情变得更快。
arr
的none、arr[i]
、path
、to
、value
、[=36=都没有关系] references/pointers,如
但是,如果 arr
、arr[i]
、path
、to
、value
is/involves a reference/pointer然后访问它们可能是缓存未命中。多次访问它们会导致多次缓存未命中(可能)。
因此,将 reference/pointer 直接存储到 value
可能比在追逐指针到达 value
时获取多个缓存未命中更有效。请记住,编译器可能无论如何都会优化这样的事情。
如果避免缓存未命中,将 value
存储为副本可能会更有效,并且复制起来相对轻松,并且您不需要修改原始值。同样,编译器很可能也会优化这些情况,如果这样做显然会提高性能的话。
这一切都取决于。 仅在证明存在问题时才进行优化。