检查指针到向量C 内的对象

Inspecting pointers to objects inside a vector C++

本文关键字:对象 向量 指针 检查      更新时间:2023-10-16

我目前正在浏览一些代码,目前我有一个公路课,带有通向车道的指针(一个私人成员),该道路类包括车道课。该车道类包含指向车辆的向量,这是另一个包含简单 get set 功能的类,以更新和获得车辆的位置,速度等。现在,我让车辆在单独的车道中移动,我允许它们切换车道,因为它在交通流量下。但是,我希望我的车辆能够不断找到距离距离的距离,即在前面的车辆,即在车辆矢量中查找并找到最接近的车辆。然后,我打算使用它来指示汽车是否应减速。我还想确保带领其余的汽车,因为一旦车辆离开显示屏高度,就应该删除它们。

我对此的尝试如下:

void Lane::Simulate(double time)
{ // This simulate allows check between other vehicles.
double forwardDistance = 0;
    for (unsigned int iV = 0; iV < fVehicles.size(); iV++) 
    {
        for(unsigned int jV = 0; jV < fVehicles.size(); jV++)
        {
            forwardDistance = fVehicles[iV]->getPosition() - fVehicles[jV]->getPosition();
        }
    }
    if(fVehicles.size() < 15)
    {
        addRanVehicle(); // Adds a vehicle, with position zero but random velocities, to each lane.
    }
    for (unsigned int iVehicle = 0; iVehicle < fVehicles.size(); iVehicle++)
    {
        fVehicles[iVehicle]->Simulate(time); // Updates position based on time, velocity and acceleration.
    }
}

可能有一个比使用此forwardDistance参数更好的方法。这个想法是在每对车辆上循环,避开点iV == jV,然后找到在Ivth车辆前面的车辆,并将两辆车之间的距离记录到setDistance()功能(这是我的功能)车辆课)。然后,我应该能够使用它来检查汽车是否太近,检查它是否可以超越,或者它是否必须制动。

目前,我不确定如何为此做出有效的循环机制。

研究在车道中执行Vehicle s有序插入的成本。如果Vehicle s根据道路上的位置进行排序,则检测两个Vehicle S的距离是孩子的游戏:

例如

for (size_t n = 0; n < fVehicles.size() - 1; n++)
{
    distance = fVehicles[n].getPosition() - fVehicles[n+1].getPosition();
}

这是o(n)vs o(n ^ 2)(使用 ^作为指数,而不是XOR)。这种简化的价格是需要有序插入到fVehicles中,这应该是O(n):一个std::binary_search来检测插入点,并且fVehicles要求释放空间以放置Vehicle

维持fVehicles的顺序在其他地方也可能是有益的。可视化列表(图形上或通过打印语句)会更加容易,当一切都以可预测的顺序和CPU时,调试在人的大脑上通常会更容易,而CPU ...他们 love 在一个不错的情况下进行,可预测的直线。有时,您会得到您没有看到的表演提升。在这里写的很棒的文章:为什么处理排序的数组比未分类的数组更快?

确定是否更好的唯一方法是尝试并测量它。

其他建议:

不要对车辆使用指针。

他们不仅难以管理,而且可以使您慢下来。如上所述,现代CPU确实擅长直线进行,并且指针可以在那条直线上扭曲。

您永远不知道在动态内存中,指针将与您所看的最后一个指针相对。但是,在Vehicle s的连续块中,当CPU加载Vehicle N时,它也可能抓住Vehicle S N 1和N 2。如果因为它们太大而不能,那就没关系了,因为它已经知道它们在哪里,而CPU正在处理,而空闲的内存频道可能会向前读取并抓住您需要的数据很快。

使用指针,您每次将Vehicle从车道移动到车道时都可以节省一些(指针通常比复制的对象便宜得多),但是在每个模拟tick中的每个循环迭代中都可能会遭受痛苦真的加起来了。C 的God-emperor Bjarne Stroustrup使用链接列表作为示例在此问题上写了一个出色的文章(注意链接列表通常比vector指针的CC_15差,但这个想法是相同的)。

>

利用std::deque

std::vector确实擅长于堆栈般的行为。您可以快速添加并从末端删除,但是如果从头开始添加或删除,则vector中的所有内容都会移动。

大多数车道插入很可能处于一端,而另一端的拆卸仅仅是因为较旧的 Vehicle s会朝着末端倾斜,因为 Vehicle s被添加到开始中,反之亦然。如果采取建议1并排序fVehicles,这是可以肯定的。一开始将在车道上添加新车辆,其中一些车道会将车道换入或从中间换出,并且将从末端拆除旧车辆。deque经过优化,用于在两端插入和卸下,因此添加新车很便宜,卸下旧车便宜,并且您只为更换车道的汽车支付全价。

std::deque上的文档

附录

尽可能利用基于范围的for。基于范围的大部分迭代逻辑并将其隐藏在您身上。

,例如这个

for (unsigned int iV = 0; iV < fVehicles.size(); iV++) 
{
    for(unsigned int jV = 0; jV < fVehicles.size(); jV++)
    {
        forwardDistance = fVehicles[iV]->getPosition() - fVehicles[jV]->getPosition();
    }
}

变成

for (auto v_outer: fVehicles) 
{ 
    for (auto v_inner: fVehicles) 
    { 
        forwardDistance = v_outer->getPosition() - v_inner->getPosition(); 
    } 
} 

如果您在计数行,看起来不会好多了,但是您不能意外

iV <= fVehicles.size()

fVehicles[iV]->getPosition() - fVehicles[iV]->getPosition()

它消除了您造成愚蠢,致命和难以遇到的错误的可能性。

让我们分解一个:

for (auto v_outer: fVehicles) 
     ^    ^        ^
  type    |        |
  variable name    | 
           Container to iterate

关于

基于范围的文档

在这种情况下,我还利用autoauto允许编译器选择数据的类型。编译器知道fVehicles包含Vehicle s的指针,因此为您替换auto。如果您稍后发现自己在重构代码,这会消除一些头痛。

auto上的文档

不幸的是,在这罐中,它也可以捕获您。如果您遵循上面的建议,fVehicles变为

std::dequeue<Vehicle> fVehicles;

这意味着auto现在是Vehicle。这使v_outer成为副本,使您复制时间和含义,含义如果您更改v_outer,则更改副本,而原件则不变。为了避免这种情况,倾向于

for (auto &v_outer: fVehicles) 

编译器擅长确定如何最好地处理该参考或是否需要它。