简体   繁体   English

C ++ STL容器和引用

[英]C++ STL Containers and references

I have a misunderstanding of how does work references, STL containers and Objects. 我对工作引用,STL容器和对象的误解有误解。

I previously look for using references in an STL container, but it seems that STL containers are "objects that store objects". 我之前在STL容器中寻找使用引用,但似乎STL容器是“存储对象的对象”。 But if I want to store objects and modifying them in the container, how can i do it ? 但是如果我想存储对象并在容器中修改它们,我该怎么办呢?

I pasted a small snipet of code illustrating my issue. 我粘贴了一小段代码来说明我的问题。

class MyObject {
    public : 
        int value;

    MyObject(const MyObject& right) : value(right.value) {}
    MyObject(int _value) : value(_value) {}

    bool operator< (const MyObject& right) const {
        return value < right.value;
    }

    void display() const {
        cout << "(" << value << ")  ";
    }
};

And in the main section 并在主要部分

cout << "Creating ... " << endl;
set<MyObject> oset;

for (int i = 0 ; i < 10 ; i++) {
     MyObject o(rand() % 1000);
     oset.insert(o);
}
cout << endl;

cout << "Display before ... " << endl;
for (MyObject o : oset)  o.display();
cout << endl;
cout << "Incrementing ... " << endl;
for (MyObject o : oset)  o.value += 1000;
cout << "Display after ... " << endl;
for (MyObject o : oset) o.display();
cout << endl;

Since the container does not use references, the incrementation is applied on copies and not the objects. 由于容器不使用引用,因此增量将应用于副本而不是对象。

I tried to use '&' insided the loop ie 我尝试使用'&'中的循环即

for (MyObject& o : oset)  o.value += 1000;

but I had the following error : 但我有以下错误:

error: invalid initialization of reference of type 'MyObject&' from expression of type 'const MyObject' 错误:从'const MyObject'类型的表达式初始化'MyObject&'类型的引用无效

You can use a reference to assign to the object - by making the loop variable o a reference: 您可以使用一个参考分配给对象-通过使循环变量o参考:

cout << "Increnting ... " << endl;
for (MyObject &o : oset)  o.value += 1000;

* EDIT * *编辑*

But because set is an ordered container, it returns const iterators. 但是因为set是一个有序容器,所以它返回const迭代器。 So if you need to amend a set perhaps you should consider using another container instead. 因此,如果您需要修改一个集合,您应该考虑使用另一个容器。 Perhaps a map? 也许是地图?

But if you really have to change a set - don't do like the code below. 但是,如果你真的需要改变一套 - 不要像下面的代码那样。 It makes valgrind very upset, as Matthieu has pointed out. 正如Matthieu指出的那样,这使得valgrind非常沮丧。 Why you can't go around erasing elements in a container whilst iterating through that container. 为什么你不能在迭代容器时绕过容器中的元素。 Such madness leads to Undefined Behavior. 这种疯狂导致了未定义的行为。

// ===== ATTENTION - NASTY CODE ALERT !! ========**
    for (MyObject &o : oset)
    {
        MyObject oNew = o;
        oNew.value += 1000;
        oset.erase(o);
        oset.insert(oNew);
    }
// =============================================**

A safer solution 更安全的解决方案

would be to create another set, copy the original set (whilst applying the required changes), then swap the new set to the old one. 将创建另一个集合,复制原始集合(同时应用所需的更改),然后将新集合交换为旧集合。

Here transform applies the lambda function over the entire set, and stores the results in the new nset set. 这里transform将lambda函数应用于整个集合,并将结果存储在新的nset集合中。 inserter creates an insertion iterator for the nset container, inserting from nset.begin(). inserter创建用于NSET容器的插入迭代器,从nset.begin插入()。 The final transform parameter - the lambda - takes an original set object and adds 1000 to it, returning the new object. 最终的变换参数 - lambda - 获取原始集合对象并向其添加1000,返回新对象。 Once the transform creates the new set, swap then places the new objects in the original container. 转换创建新集后, swap然后将新对象放在原始容器中。

set<MyObject> nset;
transform(oset.begin(), oset.end(), inserter(nset, nset.begin()),
   [](const MyObject &o) { return MyObject (o.value+1000); });
oset.swap(nset);

See this question on set updates for more info. 有关详细信息,请参阅有关集更新的此问题。

The incorrect line is for (MyObject o : oset) o.value += 1000; 不正确的行是for (MyObject o : oset) o.value += 1000; You should use for (MyObject& o : oset) o.value += 1000; 您应该使用for (MyObject& o : oset) o.value += 1000; instead 代替

Use a reference variable to refer to the object itself: 使用引用变量来引用对象本身:

for (MyObject& o : oset)  
   o.value += 1000;

Note the '&', which makes the name "o" refer to the object in the collection instead of a copy. 注意'&',它使名称“o”指代集合中的对象而不是副本。

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

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