C++: итерация по вектору векторов

Привет! Я делаю этот проект, и сейчас я пытаюсь:

  1. создать некоторые объекты и сохранить их в векторах, которые сохраняются в другом векторе V
  2. перебирать векторы внутри V
  3. перебирать объекты внутри отдельных векторов

Во всяком случае, я просто искал в Интернете и наткнулся на функцию stl for_each. Это выглядит довольно аккуратно, но у меня проблемы с этим. Я пытаюсь использовать его следующим образом:

for_each(V.begin(), V.end(), iterateThroughSmallVectors);

iterateThroug.... просто делает то же самое с переданным ему вектором..

Теперь я получаю странную ошибку времени выполнения "Векторные итераторы несовместимы". Я посмотрел на это и не могу найти никакой полезной информации по этому поводу.

Я не знаю, поможет ли это, но V — это частный вектор ‹>, хранящийся в классе A, у которого есть доступ к нему, и я пытаюсь выполнить итерацию по нему в классе B, выполнив:

A->getV().begin(), A->getV().end(), etc..

Кто-нибудь понял, что происходит?

РЕДАКТИРОВАТЬ: Хорошо, поэтому я думаю, что лучше просто опубликовать код, и где могут возникнуть проблемы...

getTiles в gameState.h:

vector<vector<tile*>> getTiles();

Циклы for_each в main.cpp:

for_each(currState->getTiles().begin(),currState->getTiles().end(), drawTiles);
.
.
void drawTiles(vector<tile*> row)
{
for_each(row.begin(), row.end(), dTile);
}
void dTile(tile *t)
{
t->draw();
}        

создание векторов:

int tp = -1;
int bCounter = 0;
int wCounter = 0;
for (int i = 0; i < 8; i++)
{
vector<tile*> row(8);
    for (int j = 0; j < 8; j++)
    {
    tile *t = new tile(tp, (i+(SIDELENGTH/2))*SIDELENGTH,
        (j+(SIDELENGTH/2))*SIDELENGTH);
    row.push_back(t);
            tp *= -1;
    }
currState->setTiles(row);
    tp *= -1;
}

и на всякий случай это может быть актуально:

void gameState::setTiles(vector<tile*> val)
{
    tiles.push_back(val);
}

Стало ли легче обнаружить проблему сейчас? Я надеюсь на это... И если вы заметите какую-нибудь глупость, которую я могу делать, пожалуйста, дайте мне знать, я новичок в C++, и указатели и ссылки все еще меня смущают.

РЕДАКТИРОВАТЬ2: Спасибо, ребята, это сработало отлично... хорошо для этой проблемы, теперь, кажется, у меня проблема с созданием плиток и их построением в векторе-строке.. кажется, что даже через вектор создается и проходит правильно , тайлов, которые должны были быть в нем, нет (они теряются после :

    for (int j = 0; j < 8; j++)
    {
    tile *t = new tile(tp, (i+(SIDELENGTH/2))*SIDELENGTH,
        (j+(SIDELENGTH/2))*SIDELENGTH);
    row.push_back(t);
            tp *= -1;
    }

петля. Если у кого-то из вас есть хорошие идеи по решению этой проблемы, пожалуйста, помогите мне;) Тем временем я буду продолжать пытаться это исправить.


person Zepee    schedule 27.11.2009    source источник
comment
Я думаю, вам нужно опубликовать точный код и особенно отметить строку, в которой вы сталкиваетесь с этой ошибкой времени выполнения.   -  person Jim Buck    schedule 28.11.2009


Ответы (3)


Каков прототип A::getV()?

Я только предполагаю, но если A::getV() не возвращает ссылку, это может объяснить сообщение об ошибке «Векторные итераторы несовместимы».

Действительно, A->getV().begin() и A->getV().end() будут двумя итераторами по разным векторам: каждый вызов A->getV() возвращает другую копию закрытого члена.

Надеюсь, это поможет вам отладить вашу проблему.


РЕДАКТИРОВАТЬ: похоже, я предвидел это правильно: после редактирования вашего вопроса с подробностями я вижу, что вы определяете

vector<vector<tile*> > getTiles();

Как следствие, в следующем утверждении:

for_each(currState->getTiles().begin(),currState->getTiles().end(), drawTiles);

Как и предполагалось выше, каждый вызов getTiles() будет возвращать отдельную временную копию вектора-члена. Как следствие, итераторы, возвращаемые из begin() и end(), поступают из разных векторов, отсюда и сообщение об ошибке, с которым вы сталкиваетесь во время выполнения.

Кроме того, как указал Чарльз в своем подробном ответе , эти временные векторы будут уничтожены к моменту достижения тела функции for_each.

Рассмотрите возможность возврата вектора по ссылке const следующим образом:

const vector<vector<tile*> >& getTiles() const;

И вы также можете изменить drawTiles, чтобы избежать еще большего количества копий:

void drawTiles(const vector<tile*>& row)

person Gregory Pakosz    schedule 27.11.2009

Что я делаю, так это: прямой путь

vector<vector<int> > vvi;
vector<vector<int> >::iterator vvi_iterator;
vector<int>::iterator vi_iterator;

for(vvi_terator = vvi.begin();vvi_iterator!=vvi.end();++vvi_iterator) {
    for(vi_iterator = (*vvi_iterator).begin();vi_iterator!=(*vvi_iterator).end();++vi _iterator) {
     cout<<*vi_iterator<<" ";
    }  
}

Это грубая идея. Я нахожу метод for_each громоздким только для выполнения двойного цикла. for_each полезен, когда вы действительно хотите выполнить некоторые вычисления для каждого элемента (например, какое-то сопоставление для каждого элемента).

person user855    schedule 27.11.2009

У вас есть пара серьезных ошибок, но сначала небольшая.

vector<vector<tile*>> getTiles();

Пока не выйдет следующий стандарт, вам нужен пробел между >.

vector< vector<tile*> > getTiles();

Эта функция возвращает vector по значению, что означает, что она создает новую копию того, что vector передается оператору return в функции. (Я предполагаю, что это объявление функции является экземпляром любого класса curState.)

Когда вы затем делаете:

for_each(currState->getTiles().begin(),currState->getTiles().end(), drawTiles);

Каждый вызов getTiles возвращает отдельную временную копию вектора. Это означает не только то, что ваши итераторы из begin() и end() исходят из разностных векторов, но и векторы будут уничтожены к тому времени, когда будет достигнуто тело функции for_each.

Похоже, вам нужно исследовать ссылки и передавать по ссылке, потому что вам нужно понять их, прежде чем вы сможете правильно использовать std::for_each в этих сценариях.

person CB Bailey    schedule 27.11.2009
comment
что в основном то, что я объяснил ;) - person Gregory Pakosz; 28.11.2009
comment
@Грегори Пакош: В то время, когда я начал этот ответ, вы еще не видели правку с «настоящим» кодом. Возможно, вы хотите украсть предупреждение о временных файлах (я думаю, это важно понять) и >>/> > для вашего ответа? - person CB Bailey; 28.11.2009
comment
@Charles - Конечно, с моей стороны, это было просто веселое чувство, когда великие умы думают одинаково. Я отредактировал ответ, включив в него сведения об уничтожении временных объектов в момент достижения тела for_each; а также ссылку на него, чтобы люди прочитали ваш комментарий о >>/> >. У вас определенно есть мой голос! - person Gregory Pakosz; 28.11.2009