简体   繁体   中英

c++ vector for each loop doesn't iterate through references?

yesterday I spent almost an our while debugging this thing and since then I can't stop thinking about it.C

I tried to implement a 2D matrix with string indexes...

class CSqrMatrix(){
  ....
  void insert(string str){
     bool b = map.insert(str,m_size).second;
     if (b){
         m_size++;
         vector<int> ve;
         for (int i = 0; i < m_vect.size(); i++) 
             ve.push_back(m_default);
         m_vect.push_back(ve);
         for (auto v : m_vect)
             v.push_back(m_default);
     }
  ...
map<string,int> map;
vector < vector<int> > m_vect;
int m_default;
int m_size;
};

after some insertions, when I tried to reach an element like

m_vect[0][0] = 8;

I got an invalid write and segfault... and the value of m_vect[0].size() was 0; I tried everything, when finally I changed the for each loop to a normal one like

for (int i = 0; i < m_vect.size(); i++){
     m_vect[i].push_back(m_default);

the program worked well...

So does that mean, that v ins't a referecne, but a new copy of the element?

Thanks (there might be typos in the code, I wrote it on the phone...)

Yes v is indeed a copy. You should do it like this:

for (auto& v : m_vect){
   v.push_back(m_default);
}

And keep in mind that std::vector copy is a deep copy for the container and for all items which is really an expensive operation. So if you want to pass through a vector of vectors ( std::vector<std::vector<T>> ) even without editing, you should pass by ref (with const if you do not want editing):

for(/*const*/ auto& v:vectors){
   //...
}
 for (auto v : m_vect) v.push_back(m_default); 

In the above form, the range-for loop iterates using copies ( v ) of the items stored in m_vect .

If you want to operate directly on references to the items in m_vect , you should be explicit about that, using auto& :

// v references items in m_vect
for (auto& v : m_vect) {
    v.push_back(m_default);
}

You may find this StackOverflow answer on using C++11 range-for interesting.

The code:

for (auto v : m_vect)
    v.push_back(m_default);

is equivalent to following ( see C++ standard [stmt.ranged] ):

{
    auto && __range = (m_vect);
    for (auto __begin = __range.begin(), __end = __range.end(); __begin != __end; ++__begin)
    {
        auto v = *__begin;      // <-- new copy in each iteration
        v.push_back(m_default); // add item to the copy
                                // the copy goes out of scope
    }
}

So, yes, v ins't a referecne, but a new copy in each iteration?

What you want is:

for (auto& v : m_vect)
    v.push_back(m_default);

That is equivalent to:

{
    auto && __range = (m_vect);
    for (auto __begin = __range.begin(), __end = __range.end(); __begin != __end; ++__begin)
    {
        auto& v = *__begin; // <-- new reference in each iteration
        v.push_back(m_default);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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