编译器(Visual C++)如何优化按索引访问矢量元素?
How compiler (Visual C++) optimize accessing vector elements by index?
>我正在尝试构建树,其中每个节点可以有无限的子节点,并从根向下传播一些值。我尝试了多种方法来实现这一目标。 首先是通过在堆上分配每个单独的节点。然后我尝试创建节点向量(不是指向节点的指针(,并使用指向该向量元素的节点指针构建树。 这是更快的解决方案,因为我猜我将节点存储在一个内存块中。这个解决方案效果很好,但如果矢量调整大小,我必须再次重建整个树。第三种选择是使用索引而不是指针来使用构建树。只有索引失效的时间是当我从矢量中删除元素时,但它只是一个节点,所以没什么大不了的(将最后一个元素与删除的元素交换(。这个解决方案是我机器上最慢的解决方案,在调试模式下(使用 Visual Studio 2019(,其他两个解决方案在调试模式下表现得更好。但是当我切换到具有优化的发布模式时,此解决方案的性能类似于我使用指向矢量元素的指针的解决方案。我读到当优化打开时,编译器可能会直接使用指针而不是索引。但我真的无法回答这个问题。所以我的问题是到底发生了什么?我是否可以假设使用索引的代码速度几乎始终相同?
使用指针的节点:
struct Node
{
void SetParent(Node* parent)
{
Parent = parent;
NextSibling = parent->FirstChild;
parent->FirstChild = this;
}
void Propagate(float x,float y)
{
Node* tmp = this;
while (tmp)
{
tmp->X += x;
tmp->Y += y;
if (tmp->FirstChild)
tmp->FirstChild->Propagate(tmp->X,tmp->Y);
tmp = tmp->NextSibling;
}
}
float X, Y;
std::string Name;
Node* Parent = nullptr;
Node* FirstChild = nullptr;
Node* NextSibling = nullptr;
}
使用索引的节点:
struct Node
{
void SetParent(std::vector<Node>& list,int parent)
{
Parent = parent;
NextSibling = list[parent].FirstChild;
list[parent].FirstChild = Index;
}
void Propagate(std::vector<Node>& list, int index, float x, float y)
{
while (index != -1)
{
list[index].X += x;
list[index].Y += y;
if (list[index].FirstChild != -1)
{
list[list[index].FirstChild].Propagate(list, list[index].FirstChild, list[index].X,
list[index].Y);
}
index = list[index].NextSibling;
}
}
float X, Y;
std::string Name;
int Index = -1;
int Parent = -1;
int FirstChild = -1;
int NextSibling = -1;
};
我们在评论中被告知,比较调试版本的性能并不是很有用。该声明是正确的,这里的问题不是发布版本做了一些神奇的事情来访问您的向量,而是调试版本因大量未进入发布版本的验证和检测代码而减慢
。考虑: 根据 stdc++ 实现,T operator[](size_t index) const
可以在调试版本中包含范围检查代码,当您直接使用指针(IIRC,即 Visual Studio stdc++ 实现中的工作方式(时,您只需绕过这些代码即可。
当然,使用指针访问的调试构建会更快,但您已经发现了许多陷阱。
总结总结:在您的情况下使用索引是完全可以的。它们不会损害性能。在此类情况下,通常不是索引受到伤害,而是这些内存访问的连贯性,您是否破坏了 CPU 缓存等。
- 在 C++ 中访问数组负索引处的内存不会返回垃圾
- 易于访问带有偏移索引的C++矢量
- 编译器(Visual C++)如何优化按索引访问矢量元素?
- 访问特定阵列位置/索引时出现分段错误
- C++ STL 数据结构常时按索引推送/弹出/随机访问,并具有指向元素的可靠指针
- 如何访问委托的paint()函数中的另一个索引?
- 如何通过索引访问枚举类
- 访问包含P的有效索引时返回空格的C++字符串
- 如何从 boost::container::vector<std::string>::iterator 访问索引和对象?
- 访问矢量元素时索引越界异常
- 对C++列表的基于索引的访问
- 如何区分数组索引的访问和赋值?
- 访问向量索引C++
- 在C 字符串中,为什么在最后一个字符之后,通过索引和()访问索引时行为是不同的
- 访问索引指向向量元素时的seg故障 - 做错了什么
- std::regex_replace:分离匹配组的访问索引
- C 用于向量中的结构访问索引或使用参考值
- 范围循环中的访问索引
- 能够访问索引大于数组长度的元素
- 如何在矢量中访问索引而不进行分段