检查指向向量 C++ 中对象的指针

Posted

技术标签:

【中文标题】检查指向向量 C++ 中对象的指针【英文标题】:Inspecting pointers to objects inside a vector C++ 【发布时间】:2017-12-08 22:05:03 【问题描述】:

我目前正在处理一些代码,并且我目前有一个道路类,带有一个指向车道的指针向量(一个私有成员),并且这个道路类包括一个车道类。这个车道类包含一个指向车辆的指针向量,这是另一个类,它包含简单的 getset 函数来更新和获取车辆的位置、速度等。现在,我让车辆在不同的车道上行驶,我允许他们切换车道,因为在交通流中也是如此。但是,我希望我的车辆不断地找到与它和前面车辆的距离,即查看车辆向量并找到最近的车辆。然后我打算用它来指示汽车是否应该减速。我还想确保领先其余的汽车,因为一旦车辆离开显示窗口高度,它们应该被删除。

我的尝试如下:

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,找到第iV辆车前面的车辆,将两辆车之间的距离记录到一个setDistance()函数中(这是一个函数我的车辆类)。然后我应该可以用它来检查汽车是否离得太近,检查它是否可以超车,或者它是否只需要刹车。

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

【问题讨论】:

计算后您似乎没有使用forwardDistance 我知道我没用过。我不确定如何创建一个有效的循环来找到车道中两辆车之间的最小距离,即车辆与前方车辆之间的距离。很抱歉,不清楚 所以你正在检查车道上当前车辆与同一车道上所有其他车辆之间的距离?大概 fVehicles 是一个向量?您想计算车道上任意两辆车之间的最小距离吗? 车辆可以在车道内改变位置吗?如果不是,那么您只需要一个计算 forwardDistance = fVehicles[n]-&gt;getPosition() - fVehicles[n-1]-&gt;getPosition(); 的循环 std::deque 可能是更好的数据结构来存储车道中的车辆。一段受监控的道路将在一侧添加汽车并从另一侧移除您在一侧添加并从另一侧移除,双端队列的行为大大超过了vector 【参考方案1】:

调查将Vehicles 有序插入通道的成本。如果Vehicles 是按照道路上的位置排序的,那么检测两个Vehicles 的距离是小菜一碟:

例如

for (size_t n = 0; n < fVehicles.size() - 1; n++)

    distance = fVehicles[n].getPosition() - fVehicles[n+1].getPosition();

这是 O(N) 与 O(N^2)(使用 ^ 作为指数,而不是 XOR)。这种简化的代价是需要对fVehicles 进行有序插入,这应该是 O(N): One std::binary_search to detect the insertion point 以及fVehicles 需要的任何改组以释放空间来放置Vehicle

维护fVehicles 的顺序在其他地方也可能是有益的。可视化列表(以图形方式或通过打印语句)将更容易,当一切都处于可预测的良好顺序时,人脑的调试通常更容易,并且 CPU ......他们喜欢运行良好,可预测的直线。有时,您会获得意想不到的性能提升。在这里写了很棒的文章:Why is it faster to process a sorted array than an unsorted array?

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

其他建议:

不要使用指向车辆的指针。

它们不仅更难管理,而且会大大减慢您的速度。如上所述,现代 CPU 非常擅长直线运动,而指针可能会在直线上产生扭结。

您永远不会真正知道动态内存中的指针相对于您查看的最后一个指针的位置。但是对于Vehicles 的连续块,当CPU 加载Vehicle N 时,它也可能会抓取Vehicles N+1 和N+2。如果因为它们太大而不能,那也没关系,因为它已经知道它们在哪里,并且当 CPU 正在处理时,空闲的内存通道可能会提前读取并获取您需要的数据很快。

每次将Vehicle 从一个通道移动到另一个通道时,使用指针可以节省一点(指针通常比要复制的对象便宜得多),但可能会在每个模拟滴答和每个循环迭代中受到影响音量确实增加了。 Bjarne Stroustrup,C++ 神帝,has an excellent write up on this problem using linked lists as an example(注意链表往往比指针的vector 差,但思路是一样的)。

利用std::deque

std::vector 非常擅长类似堆栈的行为。您可以闪电般快速地从末尾添加和删除,但如果您从开头添加或删除,vector 中的所有内容都会被移动。

大多数车道插入很可能在一端,而在另一端删除,因为旧的Vehicles 将被吸引到最后,因为Vehicles 被添加到开头,反之亦然。如果采纳建议 1 并订购 fVehicles,这是可以肯定的。新的车辆会在开始时添加到车道,少数会改变车道进入或离开中间,旧的车辆会从末端移除。 deque 针对两端的插入和移除进行了优化,因此添加新车很便宜,移除旧车很便宜,您只需为变道的汽车支付全价。

Documentation on std::deque

附录

尽可能利用基于范围的for。基于范围的 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

Documentation on Range-based for

在这种情况下,我还利用了autoauto 允许编译器选择数据类型。编译器知道fVehicles 包含指向Vehicles 的指针,因此它为您将auto 替换为Vehicle *。如果您以后发现自己要重构代码,这会消除一些令人头疼的问题。

Documentation on auto

不幸的是,在这个罐子里它也会困住你。如果你按照上面的建议,fVehicles 就变成了

std::dequeue<Vehicle> fVehicles;

这意味着auto 现在是Vehicle。这使得v_outer 成为副本,如果您更改v_outer,则需要花费您复制时间和意义,您更改副本并且原始副本保持不变。为了避免这种情况,倾向于

for (auto &v_outer: fVehicles) 

编译器擅长决定如何最好地处理该引用,或者它是否需要它。

【讨论】:

感谢您的广泛回复。如果我使用&amp;v_outer: fVehicles,这是否意味着我必须在for循环后面的代码中使用&amp;v_outer?例如,我需要使用forwardDistance = &amp;v_outer...吗? @KarandeepGiddha &amp;v_outer to be a reference 声明为fVehicles 中的元素,可以将引用视为变量的别名。该引用的使用方式与您引用的任何内容完全相同,因此这意味着没有额外的语法。 v_outer.getPosition() 将调用 getPosition 函数。了解参考资料的最佳方式是阅读 C++ 语言文本。

以上是关于检查指向向量 C++ 中对象的指针的主要内容,如果未能解决你的问题,请参考以下文章

指向另一个类 c++ 中对象向量的指针

C++,成员函数返回对包含指向 const 对象的指针的向量的 const 引用

C ++在向量迭代中删除并返回指向对象的指针

用于对包含指向自定义类对象的指针的向量进行排序的比较器

在 C++ 中,如何获取指向向量的指针?

从 2D 向量创建 1D 向量的函数(错误:表达式必须具有指向对象的指针类型)