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&lt;ofVec3f&gt;,则似乎points[0] 是初始drags[0].pos 的副本。如果是vector&lt;ofVec3f *&gt;,那么它似乎在内存中存储了一个等于&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】:

您的错误在于认为存储&amp;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&lt;ofVec3f *&gt; points,但这不起作用。实际上点可以是vector,但拖动应该是list&lt;Drag&gt; drags。我已经编辑了问题以在示例中阐明这一点。 好吧,列表方法可能有效,但它是一种蹩脚的解决方案 IMO。您提到了 Java 和 Actionscript,您需要了解在这些语言中您始终持有/传递指向对象的指针,C++ 中的等价物是在堆上分配 drag 对象并将指向它们的指针存储在容器中。 【参考方案2】:

您不能将引用存储在向量中,但可以存储 std::reference_wrapper&lt;ofVec3f&gt;

std::vector< std::reference_wrapper<ofVec3f> > v;
ofVec3f vec;
v.push_back(std::ref(vec));

存储指针也可以。您只需要使用operator*operator-&gt; 正确取消引用它。

std::vector< ofVec3f* > pv;
ofVec3f vec;
pv.push_back(&vec);
pv.front()->x;

关于地址相等 地址与拖动对象的地址相同是正常的。向量是第一个成员,因此它们具有相同的地址(仅保证 POD 类型实际上是这种情况)。

【讨论】:

我认为这并不能解决这里的真正问题,即存储不相关的指针/引用,请参阅我的答案。 @pmr: std::reference_wrapper (C++11) 在 openframeworks 中尚不可用。正如你所说,指针已经被使用(除了它是[0]->而不是front()->),这不起作用。

以上是关于C++ 在向量中存储对类成员的引用的主要内容,如果未能解决你的问题,请参考以下文章

向量中不存在 C++ 字符串成员变量

c ++在析构函数中删除向量类成员内存

运行时在构造函数中初始化向量类成员——C++

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

如何获取 C++ 类成员向量的大小?

如何访问和存储向量类型的结构成员?