Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用指针是预取数据的好方法吗?_C++_Pointers_Caching_Memory - Fatal编程技术网

C++ 使用指针是预取数据的好方法吗?

C++ 使用指针是预取数据的好方法吗?,c++,pointers,caching,memory,C++,Pointers,Caching,Memory,最近我读了一些关于编写缓存友好的代码的文章,我试图在实践中使用它,但是我偶然发现了一些稍微令人困惑的东西 据我所知,预取数据允许cpu专注于手头的工作,而不会因为必须从内存中的不同位置获取数据而分心。我在Mike Acton关于面向数据设计的讲座中看到的一个具体示例甚至提到在本地存储类成员有利于提高性能。(例如,在for循环的条件中使用int some_count=m_SomeCount,而不是使用成员m_SomeCount本身,因为类成员存储在内存中局部变量以外的其他位置,因此无法正确缓存)

最近我读了一些关于编写缓存友好的代码的文章,我试图在实践中使用它,但是我偶然发现了一些稍微令人困惑的东西

据我所知,预取数据允许cpu专注于手头的工作,而不会因为必须从内存中的不同位置获取数据而分心。我在Mike Acton关于面向数据设计的讲座中看到的一个具体示例甚至提到在本地存储类成员有利于提高性能。(例如,在for循环的条件中使用int some_count=m_SomeCount,而不是使用成员m_SomeCount本身,因为类成员存储在内存中局部变量以外的其他位置,因此无法正确缓存)

话虽如此,请参见下面的(琐碎的)代码片段:

// Fetching the element several times
m_Entities[entity_id].status &= ~Entity::StatusFlags::kActive;
m_Entities[entity_id].components.clear();
m_Entities[entity_id].DoSomething(); 

// Fetching the element once, though now a pointer is used
Entity::Entity* entity = &m_Entities[entity_id];
entity->status &= ~Entity::StatusFlags::kActive;
entity->components.clear();
entity->DoSomething();
使用第二种方法(使用指针),您只需从向量中获取元素一次,我想知道这是否真的有利于“缓存友好性”和总体性能,因为每次您想要修改元素时仍然需要取消对指针的引用


非常感谢

我不确定我是否会称之为“预取”——对我来说,这个术语指的是更低级的技术,它将加载缓存或管道,以预期CPU很快就会需要数据

然而,撇开术语上的差异不谈,现在几乎所有的编译器(启用了优化)都会将表达式
m\u Entities[entity\u id]
折叠到寄存器中,用作后续访问的指针。除非有可能对
m_实体
entity_id
使用别名,以便在后续使用中更改它们

即使您知道不会(或应该)出现这种别名,编译器有时也没有足够的信息来保证这一点

使用本地指针可以确保编译器不必担心别名的可能性

它仍然是一种优化,在大多数情况下不太可能有明显的帮助,尽管我确实遇到过这样的代码,它还可以使代码更具可读性。我认为很难说这会降低代码的可读性,如果不需要的话,编译器可以随意优化指针的存储位置。我不确定它是否会变成一种悲观(一种优化)

我能看到的唯一真正的缺点是:

  • 有人可能会说这是不必要的或可读性较差
  • 如果代码依赖于别名(或更改索引表达式的非别名副作用),则行为会有所不同,并且引入了错误

首先编写清晰、易懂、可维护的代码。然后通过分析来确定是否需要像这样的微优化。生成优化的装配并自己寻找。考虑到您刚刚发布的示例,除非
m_Entities
属于重载
运算符[]
的类型,否则我真诚地怀疑您在优化代码方面是否获得了任何好处。此外,总体而言,编译器在您所说的优化方面相当出色。正如@NathanOliver所说的,先编写好代码,然后进行优化。在相当多的情况下,过早的优化实际上可能会使您的代码变慢,因为它可能会抢先编译器生成可能更优化的代码路径。您考虑得太多了。写清楚易懂的代码。如果它的表现不如你所期望的那么好,那么就对它进行分析——只有这样才能尝试优化。我的钱是你不能预先猜出哪段代码是性能瓶颈。尝试预先进行微优化只是浪费时间——相信你的优化器,或者在牺牲代码清晰性之前证明它是错误的。这与其说是优化特定项目的性能,不如说是了解在幕后发生了什么。我明白,在优化细节之前,您应该首先确保您的代码实际上是好的。但这并不意味着我不想知道如何优化细节!非常感谢。是的,对不起,我对缓存优化的整个概念都很陌生。所以现在我想知道,如果
entity\u id
是函数的
int
参数(它甚至不需要是
const
),那么
m\u Entities[entity\u id]
就不应该有别名,这对编译器来说足够了吗然后,除非地址已提供给其他函数,否则不能对其进行别名。