简体   繁体   English

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

[英]Inspecting pointers to objects inside a vector C++

I am currently going through some code and I currently have a road class, with a vector of pointers to lanes (a private member), and this road class includes a lane class. 我目前正在通过一些代码,并且目前有一个道路类,其中包含指向车道的指针(私有成员),并且这个道路类包括一个车道类。 This lane class contains a vector of pointers to vehicles, which is another class that contains simple get and set functions to update and obtain a vehicle's position, velocity etc. Now, I have vehicles moving in separate lanes and I allow them to switch lanes, as it is so in traffic flow. 这个车道类别包含指向车辆的指针向量,这是另一个类别,其中包含简单的getset函数来更新和获取车辆的位置,速度等。现在,我有在不同车道中行驶的车辆,并且允许他们切换车道,就像在交通流中一样。 However, I would like my vehicles to continuously find a distance from it and the vehicle in front, ie, look in the vehicles vector and find the closest vehicle. 但是,我希望我的车辆不断寻找与它和前方车辆的距离,即查看车辆矢量并找到最近的车辆。 Then I intend to use that to instruct whether a car should decelerate or not. 然后,我打算用它来指示汽车是否应该减速。 I would also like to make sure that cars which are leading the rest, since once a vehicle leaves the displaywindow height, they should be deleted. 我还想确保其他车辆处于领先地位,因为一旦车辆离开显示窗口高度,就应将其删除。

My attempt at this is as follows: 我的尝试如下:

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.
    }
}

There may be a much better method than using this forwardDistance parameter. 可能有比使用此forwardDistance参数更好的方法。 The idea is to loop over each pair of vehicles, avoid the point iV == jV , and find the vehicle which is in front of the iVth vehicle, and record the distance between the two vehicles into a setDistance() function (which is a function of my Vehicle class). 这个想法是循环每对车辆,避开点iV == jV ,找到在第iVth车辆前面的车辆,并将两辆车辆之间的距离记录到setDistance()函数中(这是一个我的车辆类的功能)。 I should then be able to use this to check whether a car is too close, check whether it can overtake, or whether it just has to brake. 然后,我应该能够使用它来检查汽车是否离得太近,是否可以超车或是否只需要刹车。

Currently, I am not sure how to make an efficient looping mechanism for this. 目前,我不确定如何为此建立有效的循环机制。

Investigate the cost of performing an ordered insert of Vehicle s into the lane. 研究执行有序插入Vehicle到车道的成本。 If the Vehicle s are ordered according to position on the road, detecting the distance of two Vehicle s is child's play: 如果根据道路上的位置订购Vehicle ,则检测两辆Vehicle的距离是儿童游戏:

Eg 例如

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

This is O(N) vs O(N^2) (using ^ as exponent, not XOR). 这是O(N)vs O(N ^ 2)(使用^作为指数,而不是XOR)。 The price of this simplification is the requiring ordered insert into fVehicles , and that should be O(N): One std::binary_search to detect the insertion point and whatever shuffling is required by fVehicles to free up space to place the Vehicle . 这种简化的代价是要求将有序插入fVehicles ,并且价格应为O(N): 一个std::binary_search以检测插入点以及fVehicles需要进行任何改组以腾出空间来放置Vehicle

Maintaining ordering of fVehicles may be beneficial in other places as well. 在其他地方,保持fVehicles排序也可能是有益的。 Visualizing the list (graphically or by print statements) will be much easier, debugging is generally easier on the human brain when everything is in a nice predictable order, and CPUs... They LOVE going in a nice, predictable straight line. 可视化列表(以图形方式或通过打印语句)将更加容易,当一切都以可预测的良好顺序运行时,在人脑上调试通常会更容易,而CPU ...他们喜欢以可预测的良好直线前进。 Sometimes you get a performance boost that you didn't see coming. 有时,您会获得看不到的性能提升。 Great write-up on that here: Why is it faster to process a sorted array than an unsorted array? 关于此的精彩文章: 为什么处理排序数组要比未排序数组快?

Only way to be sure if this is better is to try it and measure it. 确保这种方法更好的唯一方法就是尝试并进行测量。

Other Suggestions: 其他建议:

Don't use pointers to the vehicles. 不要使用指向车辆的指针。

Not only are they harder to manage, they can slow you down quite a bit. 它们不仅难于管理,而且会使您放慢速度。 As mentioned above, modern CPUs are really good at going in straight lines, and pointers can throw a kink in that straight line. 如上所述,现代CPU确实擅长直线运动,并且指针可能会沿直线运动。

You never really know where in dynamic memory a pointer is going to be relative to the last pointer you looked at. 您永远不会真正知道指针在动态内存中将相对于您查看的最后一个指针的位置。 But with a contiguous block of Vehicle s , when the CPU loads Vehicle N it can possibly also grab Vehicle s N+1 and N+2. 但是如果有一个相邻的Vehicle块,则当CPU加载Vehicle N时,它也可能会抓取Vehicle N + 1和N + 2。 If it can't because they are too big, it doesn't matter much because it already knows where they are, and while the CPU is processing, and idle memory channel could be reading ahead and grabbing the data you're going to need soon. 如果不是因为它们太大而已,那就没关系了,因为它已经知道它们的位置,并且在CPU处理过程中,空闲内存通道可能会提前读取并获取您需要的数据不久。

With the pointer you save a bit every time you move a Vehicle from lane to lane (pointers are usually much cheaper than objects to copy), but may suffer on each and every loop iteration in each and every simulation tick and the volume really adds up. 使用指针可以在每次将Vehicle从一个车道移到另一个车道时节省一些时间(指针通常比要复制的对象便宜得多),但是在每个模拟滴答声中的每个循环迭代中都可能会受到影响,并且体积实际上加起来。 Bjarne Stroustrup, God-Emperor of C++, has an excellent write up on this problem using linked lists as an example (Note linked list is often worse than vector of pointer, but the idea is the same). B ++的神皇Bjarne Stroustrup 用链表作为例子很好地解决了这个问题 (注意链表通常比指针的vector差,但是思想是相同的)。

Take advantage of std::deque . 利用std::deque

std::vector Is really good at stack-like behaviour. std::vector确实擅长堆栈式行为。 You can add to and remove from the end lightning fast, but if you add to or remove from the beginning, everything in the vector is moved. 您可以快速添加到结尾,也可以从结尾删除,但是如果从一开始添加或删除, vector所有内容都会移动。

Most of the lane insertions are likely to be at one end and the removals at the other simply because older Vehicle s will gravitate toward the end as Vehicle s are added to the beginning or vise versa. 大多数车道的插入很可能在一端,而另一条车道的去除则仅是因为随着Vehicle的增加,较旧的Vehicle将趋向于末端,反之亦然。 This is a certainty if suggestion 1 is taken and fVehicles is ordered. 如果采用建议1并订购了fVehiclesfVehicles New vehicles will be added to the lane at the beginning, a few will change lanes into or out of the middle, and old vehicles will be removed from the end. 新车将在开始时添加到车道,一些车道将更改为进入或驶出中间的车道,而旧车将从末尾移除。 deque is optimized for inserting and removing at both ends so adding new cars is cheap, removing old cars is cheap and you only pay full price for cars that change lanes. deque已针对两端的插入和移除进行了优化,因此添加新车很便宜,移除旧车很便宜,并且您只需为更改车道的车付全价。

Documentation on std::deque 关于std::deque文档

Addendum 附录

Take advantage of range-based for where possible. 基于范围的充分利用for在可能的情况。 Range-based for takes most of the iteration logic away and hides it from you. 基于范围的for消除了大部分迭代逻辑,并向您隐藏了它。

Eg this 例如这个

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();
    }
}

becomes

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

It doesn't look much better if you are counting lines, but you can't accidentally 如果您要数行,它看起来不会好多了,但是您不会偶然

iV <= fVehicles.size()

or 要么

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

It removes the possibility for you to make silly, fatal, and hard-to-spot errors. 它消除了您犯傻的,致命的和难以发现的错误的可能性。

Let's break one down: 让我们分解一下:

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

Documentation on Range-based for 基于范围的文档

In this case I'm also taking advantage of auto . 在这种情况下,我还利用了auto auto allows the compiler to select the type of the data. auto允许编译器选择数据类型。 The compiler knows that fVehicles contains pointers to Vehicle s, so it replaces auto with Vehicle * for you. 编译器知道fVehicles包含指向Vehicle的指针,因此它会为您用Vehicle *代替auto This takes away some of the headaches if you find yourself refactoring the code later. 如果您以后发现自己重构代码,这将消除一些麻烦。

Documentation on auto auto文档

Unfortunately in this cans it can also trap you. 不幸的是,在这个罐子里,它也会困住你。 If you follow the suggestions above, fVehicles becomes 如果您遵循上述建议, fVehicles将变为

std::dequeue<Vehicle> fVehicles;

which means auto is now Vehicle . 这意味着auto现在是Vehicle Which makes v_outer a copy, costing you copying time and meaning if you change v_outer , you change a copy and the original goes unchanged. 这使v_outer成为副本,从而v_outer了您的复制时间,并且意味着如果您更改v_outer ,那么您就更改了副本,而原始副本保持不变。 to avoid that, tend toward 为了避免这种情况,倾向于

for (auto &v_outer: fVehicles) 

The compiler is good at deciding how best to handle that reference or if it even needs it. 编译器擅长决定如何最好地处理该引用,或者甚至需要它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM