迭代二维STL向量C++

11

我目前正在尝试打印游戏中玩家移动的历史记录。在每个回合结束时,每个玩家都会向正方向或负方向移动一定距离,并将此记录为运动向量中的整数。最终,我想对每个玩家的移动方向与时间进行绘图,但我无法从二维向量中提取数据。

因此,我尝试的第一件事是迭代并打印所有元素,但这不会编译:

void output_movement(const std::vector< std::vector<int> > & movement){

    std::vector< std::vector<int> >::iterator row;
    std::vector<int>::iterator col;
    for (row = movement.begin(); row != movement.end(); ++row) {
         for (col = row->begin(); col != row->end(); ++col) {
            std::cout << **col;
         }
    }

}
编译器给出了我不太理解的错误信息:
hg_competition.cpp:45: error: no match foroperator=’ in ‘row = ((const std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >*)money_movement)->std::vector<_Tp, _Alloc>::begin [with _Tp = std::vector<int, std::allocator<int> >, _Alloc = std::allocator<std::vector<int, std::allocator<int> > >]()’
/usr/include/c++/4.4/bits/stl_iterator.h:669: note: candidates are: __gnu_cxx::__normal_iterator<std::vector<int, std::allocator<int> >*, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > >& __gnu_cxx::__normal_iterator<std::vector<int, std::allocator<int> >*, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > >::operator=(const __gnu_cxx::__normal_iterator<std::vector<int, std::allocator<int> >*, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > >&)

非常感谢您的任何帮助!

5个回答

16

如果 vector 是一个常量引用,您需要使用 const_iterator。此外,只需要解引用一次即可输出col

void output_movement(const std::vector< std::vector<int> > & movement){

    std::vector< std::vector<int> >::const_iterator row;
    std::vector<int>::const_iterator col;
    for (row = movement.begin(); row != movement.end(); ++row) {
         for (col = row->begin(); col != row->end(); ++col) {
            std::cout << *col;
         }
    }
}

编辑:使用typedef可以使您的代码更易读。

typedef std::vector<int> Vector;
typedef std::vector<Vector> DoubleVector;

void output_movement(
    const DoubleVector& movement
)
{
    for (DoubleVector::const_iterator row = movement.begin(); row != movement.end(); ++row) {
         for (Vector::const_iterator col = row->begin(); col != row->end(); ++col) {
            std::cout << *col;
         }
         std::cout << std::endl;
    }
}

1
我认为,如果你要重写代码,也许值得在for循环中适当地放置rowcol声明以实现正确的作用域。 - Matthieu M.
如果将 output_movement 改名为 operator<<,或许更符合C++的编程规范。 - Philipp
1
@Philipp:我不确定。重载运算符总是很棘手的,特别是当可能有几种可能的显示方式时。 - Matthieu M.

12

2D向量被声明为const,因此需要使用const_iterator而不是iterator

您也不应该对col进行双重解引用。它是一个迭代器,因此只需要解引用一次。

void output_movement(const std::vector< std::vector<int> > & movement){ 

    std::vector< std::vector<int> >::const_iterator row; 
    std::vector<int>::const_iterator col; 
    for (row = movement.begin(); row != movement.end(); ++row) { 
         for (col = row->begin(); col != row->end(); ++col) { 
            std::cout << *col; 
         } 
    } 

} 

4

const对象返回const_iterators,所以只需在所有地方将iterator替换为const_iterator。这也可以防止向量的不必要修改。

这是Sam和Mathieu建议的结合体:

#include <ostream>
#include <vector>

typedef std::vector<int> Vector;
typedef std::vector<Vector> DoubleVector;


template<typename Char, typename Traits>
std::basic_ostream<Char, Traits>&
operator<<(std::basic_ostream<Char, Traits>& stream,
           const DoubleVector& movement) {
    for (DoubleVector::const_iterator row = movement.begin(); row != movement.end(); ++row) {
         for (Vector::const_iterator col = row->begin(); col != row->end(); ++col) {
            stream << *col;
         }
    }
return stream;
}

3
约翰,你建议使用lambda表达式,但如果C++11可用,我更喜欢。
for (auto& row : movement) {
     for (auto& elem : row) {
        std::cout << elem;
     }
}

+1 对于干净的基于范围的循环——虽然没有必要使用'&',不是吗? - Christian Severin
Christian:是的,有!否则,每一行都会被复制并迭代。第二个引用不是那么关键。 - Petter
Ben:哦,那个:是的,当然。但是,为了确保您不会意外更改rowelement,最好写成 const auto& ,不是吗? - Christian Severin

0
哦天啊,任何东西都比那一堆for循环好。这里有一些替代方案。选择你喜欢的即可。
typedef vector<int> VI;
typedef vector<VI> VVI;


namespace std {
    ostream& operator<<(ostream& o, const VI& v) {
        copy (v.begin(), v.end(), ostream_iterator<int>(cout));
        return o;
    }
}
void output_movement (const VVI& m) {
    copy (m.begin (), m.end (), ostream_iterator<const VI&>(cout));
}

或者,

void output_movement (const VVI & m) {
    for_each (m.begin(), m.end(), [](const VI& v){ 
                for_each (v.begin(), v.end(), [](int i){ cout << i; });
                });
}

或者,我的个人偏好(boost/foreach.hpp),

void output_movement (const VVI & m) {
    foreach (const VI& v, m)
        foreach (int i, v)
            cout << i;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接