C++ 在向量中存储对类成员的引用
Posted
技术标签:
【中文标题】C++ 在向量中存储对类成员的引用【英文标题】:C++ store reference to class member in a vector 【发布时间】:2012-11-23 01:02:19 【问题描述】:考虑一个 Drag 对象:
class Drag
public:
Drag(ofVec3f _pos);
ofVec3f pos;
创建新实例时存储位置:
Drag::Drag(ofVec3f _pos)
pos = _pos;
鼠标移动时位置更新:
void Drag::mouseMoved()
pos.x = ofGetMouseX();
pos.y = ofGetMouseY();
在应用程序的主类(openframeworks中的testApp)中:
class testApp : public ofBaseApp
public:
vector<Drag> drags;
vector<ofVec3f *> points;
按下鼠标时创建一个拖动并将其位置存储在一个称为点的向量中:
void testApp::mousePressed(int x, int y, int button)
Drag drag = Drag(ofVec3f(ofGetMouseX(), ofGetMouseY(), 0));
drags.push_back(drag);
points.push_back(&drag.pos);
现在,当拖动移动时,我可以看到它的位置更新,但 points[0] 没有改变:
void testApp::update()
if (!drags.size()) return;
cout << drags[0].pos.x << ", " << drags[0].pos.y << endl;
cout << &points[0]->x << ", " << &points[0]->y << endl;
如果点的类型是vector<ofVec3f>
,则似乎points[0] 是初始drags[0].pos 的副本。如果是vector<ofVec3f *>
,那么它似乎在内存中存储了一个等于&drag的地址。
如何使 points[0] 指向 drags[0].pos 并在 drags[0].pos.x 和 drags[0].pos.y 更新时更新其 x,y 值?
如何使 points[0] 成为 drags[0].pos 的引用?
编辑:感谢 yonilevy 为我指明了正确的方向。这是工作示例,使用 std::list 更新:
// testApp.h
list<Drag> drags;
vector<ofVec3f *> points;
// testApp::mousePressed
drags.push_back(Drag(ofVec3f(ofGetMouseX(), ofGetMouseY(), 0)));
points.push_back(&drags.back().pos);
【问题讨论】:
【参考方案1】:您的错误在于认为存储&drag.pos
将帮助您跟踪drag
的位置,而实际上您存储的地址在该范围结束时将变得毫无意义。由于drag
是一个局部变量,存在于堆栈中,它会在创建它的作用域结束时消失。在这种情况下,即使存储 push_back
时由向量创建的 drag
副本的地址也无济于事,因为一旦向量的物理大小增长并且必须移动它的所有内容,它也会变得无效东西到内存中的不同位置。
您可以做的是确保您推送到向量的实际 Drag 对象仍然是唯一的,方法是在堆上分配它并将指向它的(智能)指针推送到向量中。这样一来,您就可以像以前一样在向量中保留指向其内部 pos
的指针,并且只要另一个向量存在,它就会有效。
【讨论】:
如果你推动一堆其他阻力,它将停止工作,正如我在答案中提到的那样 - 一旦向量达到其全部内存容量,它就会重新分配并复制其所有包含的对象,并且这将使您的指针再次无效。要么使用 std::list 要么在堆上分配阻力。 你是对的。在更多的 drags[n].pos 被推入点后,它确实停止了工作。我尝试使用 std:list 但结果相同。还没试过在堆上分配,真的有必要吗?在 Actionscript 或 Java 中,这将是简单的 points[n] = drags[n].pos,完成。在 C++ 中一定有一种简单的方法可以做到这一点...感谢您迄今为止的帮助。 好的,我让它与 std::list 一起工作。在我之前的评论中,我使用了list<ofVec3f *> points
,但这不起作用。实际上点可以是vectorlist<Drag> drags
。我已经编辑了问题以在示例中阐明这一点。drag
对象并将指向它们的指针存储在容器中。
【参考方案2】:
您不能将引用存储在向量中,但可以存储 std::reference_wrapper<ofVec3f>
。
std::vector< std::reference_wrapper<ofVec3f> > v;
ofVec3f vec;
v.push_back(std::ref(vec));
存储指针也可以。您只需要使用operator*
或operator->
正确取消引用它。
std::vector< ofVec3f* > pv;
ofVec3f vec;
pv.push_back(&vec);
pv.front()->x;
关于地址相等 地址与拖动对象的地址相同是正常的。向量是第一个成员,因此它们具有相同的地址(仅保证 POD 类型实际上是这种情况)。
【讨论】:
我认为这并不能解决这里的真正问题,即存储不相关的指针/引用,请参阅我的答案。 @pmr: std::reference_wrapper (C++11) 在 openframeworks 中尚不可用。正如你所说,指针已经被使用(除了它是[0]->而不是front()->),这不起作用。以上是关于C++ 在向量中存储对类成员的引用的主要内容,如果未能解决你的问题,请参考以下文章