引用二维向量中的元素 (c++)

Posted

技术标签:

【中文标题】引用二维向量中的元素 (c++)【英文标题】:Reference to element in 2d vector (c++) 【发布时间】:2010-02-05 12:04:27 【问题描述】:

我在粒子系统中有一个名为 Spring 的类。构造函数如下:

Spring(Particle& _a, Particle& _b);

我有一个粒子向量,我使用

Spring mySpring = Spring(myParticles.at(j),myParticles.at(j+1));

在循环内添加两个粒子之间的弹簧力。到目前为止一切正常。 但是,我想使用粒子的二维向量。那就是:

Spring mySpring = Spring(myParticles.at(i).at(j),myParticles.at(i).at(j+1));

而且我没有得到对粒子的引用。在第一个示例中,每当我更改 spring 类中的粒子时,向量中的粒子都会更改。在第二个示例中,更改仅在本地进行。如何更改 2D Vector 中的粒子?

编辑: 我试着把一些事情说清楚:

我有一些粒子系统,每个系统都由许多粒子组成。每个粒子只应与与自身处于同一系统中的其他粒子相互作用。因此,我有一个粒子系统向量,每个粒子系统都是粒子对象的向量。 (这使得二维向量)。第一个维度 (i) 是系统,第二个维度 (j) 是单个粒子。 系统中的粒子相互影响(碰撞、躲避等等)并且它们的位置发生变化。并且向量得到“更新”。 (即参考有效)。

但是,我有第二个 (1d) 弹簧力向量。弹簧力也用于更新粒子的位置。 我的构造函数执行以下操作:

Spring::Spring(Particle& _a, Particle& _b) 
    a=&_a;
    b=&_b; 

a 和 b 是粒子*。所以我在二维向量中存储了指向两个粒子的指针。另一个函数 Spring.doSpring() 改变粒子的位置。

a->pos.x=300;

a->velocity+=something..

在我发布的第一个示例中,我只使用了一个粒子系统,因此不需要二维向量。一切正常。向量中的粒子得到更新。 但是在第二个示例中,我的程序运行了,但不知何故,无论 doSpring 函数做什么,二维向量中的粒子都不会更新。

【问题讨论】:

你是如何声明“myParticles”的? 嘿,来自drdobbs.com/cpp/184401863 的提示:“不要过度立法命名,但要使用一致的命名约定:只有两个必须做的事情:a) 永远不要使用“卑鄙的名字”以下划线开头或包含双下划线;" Herb Sutter 和 Andrei Alexandrescu 的话 【参考方案1】:

将引用/指针指向向量内的元素的最常见问题之一是重新分配。例如,如果你 push_back,向量可能会超出其容量,分配一个新的内存块,复制所有内容,然后释放旧块。如果你已经对向量内的元素进行了引用或指针,这些仍然指向旧块,现在是死内存,这是一个严重的错误!

所以我猜你的粒子效果会不断向你的粒子向量中添加新粒子,这在某些时候会导致向量在超出容量时重新分配。 Spring 类存储的指针并没有更新,所以指向死内存并且对实际粒子没有影响,它被向量移动到其他地方。

不要将引用或指针指向向量内的元素。 使用指针向量、列表或其他不会在实际元素。如果必须,请使用 iterators 到向量内的元素。在调试版本中,假设您已检查 STL 实现,如果在向量重新分配自身后通过迭代器访问元素,您将收到调试警报。

【讨论】:

但这不会导致空指针导致应用程序崩溃吗?因为我的应用程序没有崩溃,所以元素没有得到更新。但是,这是一个很好的答案,我没有考虑重新分配。 不,没有任何东西被设置为空指针:vector 不知道 Spring 类中的指针,因此永远不要尝试更改它们。指针没有被修改或为空,它们只是指向一个死内存位置。因为内存可能在您的进程中的某个位置,所以允许读取和写入,尽管您可能正在破坏应用程序的内存。【参考方案2】:

您所做的看起来不错 - 以下代码创建了一个“2D”向量并说明 .at().at() 构造确实为您提供了参考:

#include <vector>
#include <iostream>
using namespace std;

int main() 
    vector <vector<int> > vi;
    vi.push_back( vector <int>() );
    vi.at(0).push_back( 42 );
    cout << vi.at(0).at(0) << endl;    // prints 42
    vi.at(0).at(0) = 666;
    cout << vi.at(0).at(0) << endl;    // prints 666

【讨论】:

【参考方案3】:

我认为来自 C++ FAQ Lite 的 this series 应该会有所帮助。

请不要被“运算符重载”标头所迷惑。您绝对应该从那里阅读 13.10、13.11 和 13.12。

【讨论】:

【参考方案4】:

如果我理解正确,您想使用std::vector 创建一个二维粒子数组?

如果是这样,您可以将其声明为:std::vector&lt;std::vector&lt;Particle&gt; &gt;。然后,您甚至可以使用 [][] 命名法来访问元素。 (Danger Will Robinson!使用此运算符时不进行边界检查

但是,如果这个二维数组主要包含零,那么使用带有索引作为键的 map 可能是可以的。

【讨论】:

从他的代码 (.at(i).at(j)) 来看,他已经在使用向量的向量了。 从上面的例子来看,这看起来正是他已经在尝试做的事情(“at(...).at(...)”部分)。

以上是关于引用二维向量中的元素 (c++)的主要内容,如果未能解决你的问题,请参考以下文章

如何访问在 C++ 中通过引用传递的列表/向量的元素

C++:对象、对对象的引用、对带有和不带有函数的向量元素的引用——观察到的性能差异

每个循环的 c++ 向量不会遍历引用?

从向量中删除取消引用的元素

C ++:在向量中插入啥 - 指针或引用,向量何时复制它的元素?

关于C++中的二维向量