Ошибки C ++ с указанным объектом - как отладить? - PullRequest
0 голосов
/ 06 марта 2012

После помощи в этом вопросе я использую ссылку на мой класс 'Mover' для манипулирования объектом (как частью набора) в векторе. У меня, однако, есть проблемы, и я не могу точно определить причину этого. Похоже, что как только я достиг 30-35 объектов в моем векторе (добавленных через псевдослучайные интервалы), программа останавливается. Никаких сбоев, просто остановка, и я должен вручную завершить задачу (CTRL-C не работает).

Кажется, моя проблема заключается в этих кусочках кода. Мой оригинал:

int main() {
std::vector< Mover > allMovers;
std::vector< Mover >::iterator iter = allMovers.begin(); 
//This code runs to the end, but the 'do stuff' lines don't actually do anything.
Mover tempMover;
//Other code
while(iter < allMovers.end()) {
tempMover = *iter;
//Do stuff with tempMover
//Add another tempMover at a random interval
allMovers.push_back(CreateNewMover());
iter++;
}
//Other code
}

Мое обновление после предыдущего вопроса, указанного выше:

int main() {
std::vector< Mover > allMovers;
std::vector< Mover >::iterator iter = allMovers.begin(); 
//This code crashes once about 30 or so items exist in the vector, but the 'do stuff' lines do work.
//Other code
while(iter < allMovers.end()) {
Mover& tempMover = *iter;
//Do stuff with tempMover
//Add another tempMover at a random interval
allMovers.push_back(CreateNewMover()); //Crashes here.
iter++;
}
//Other code
}

Есть идеи, как это отследить? У меня есть std :: couts повсюду, чтобы пометить, где код для меня. Авария (в то время как происходит с различным количеством объектов) всегда приводит к сбою в push_back (), несмотря на то, что она успешно работала несколько раз за один и тот же прогон до аварии.

EDIT

Хотя я принимаю и (думаю) понимаю ответ re: iterators, я не понимаю, почему код DOES работает полностью, когда я не использую ссылку на объект? (Первый кодовый блок).

Другая редакция В случае, если кто-то искал это специально, часть моего вопроса не была адресована: «Как отлаживать? Как новичок в C ++, я не знал об отладчике GDB (используя MinGW). Теперь, когда я узнал об этом, было очень полезно найти источник этих проблем.

Ответы [ 4 ]

4 голосов
/ 06 марта 2012

Когда вектор перераспределяет свою память, все итераторы становятся недействительными (вместе с любой ссылкой или указателем на любой элемент).Поэтому иногда ваш push_back делает недействительным iter, и попытка использовать его впоследствии приводит к неопределенному поведению.

Самое простое решение - использовать индекс, а не итератор.В качестве альтернативы, если вы можете вычислить верхнюю границу для максимального размера вектора, вы можете вызвать reserve перед циклом, чтобы убедиться, что он никогда не перераспределяется.Или вы можете использовать std::list, чьи итераторы сохраняются при вставке новых элементов.

ОБНОВЛЕНИЕ: Что касается вашего редактирования, оба дают неопределенное поведение.Может случиться так, что в первом случае вы не аварийно завершите работу, потому что у вас нет доступа к свисающей ссылке (а при обращении к tempMover во втором вполне может произойти сбой), и тогда память будет перераспределена на более низком уровне.адрес, чем раньше, поэтому условие while (в котором используется < вместо более обычного !=) немедленно выходит из цикла.Или может происходить что-то совершенно другое - это природа неопределенного поведения.

1 голос
/ 06 марта 2012

Вы (вероятно) делаете это неправильно.

Дело в том, что смешивание итерации над контейнером и манипулирование структурой контейнера (здесь добавление объектов) чрезвычайно подвержено ошибкам.

Каждый раз, когда вы добавляете элемент в allMovers, существует риск того, что iter станет недействительным. Любое использование iter после того, как оно было признано недействительным, является Неопределенное поведение .

Можно сделать это правильно:

iter = allMovers.insert(allMovers.end(), CreateNewMover());

однако это вообще плохая идея.

Мой совет: запретить этот вид кода из вашей кодовой базы в целом. Каждый случай - ошибка в процессе становления. Найдите другой алгоритм.

1 голос
/ 06 марта 2012

Из документации для push_back () :

Если новый размер () не больше емкости (), никакие итераторы или ссылки не будут признаны недействительными.В противном случае все итераторы и ссылки становятся недействительными.

При достижении 30 или некоторых объектов new size() > capacity(), что приводит к аннулированию итератора iter, который отменяется, вызывая неопределенное поведение.

1 голос
/ 06 марта 2012

Возможно, вам придется изменить строку, содержащую инструкцию while:

while(iter != allMovers.end()) {

оператор < обычно работает нормально с вектором, но у меня были лучшие результаты, используя !=, который работаетс другими контейнерами, а также, кажется, используется в большем количестве примеров кода.


Обновление

Вы можете заменить цикл while эквивалентным for цикл такой:

for(std::vector<Mover>::iterator iter = allMovers.begin(); iter != allMovers.end(); ++iter)
{

Это имеет то преимущество, что приращение итератора iter "имеет свое место" и с меньшей вероятностью будет забыто.


Обновление 2

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

int main() 
{
    std::vector< Mover > allMovers;

    //Other code

    while(1) // this loop will add new movers as long as it succeeds to create one
    {
        Mover new_mover = CreateNewMover();
        if ( IS EMPTY (new_mover) )  // pseudocode. Check if the previous
             break;                  // CreateNewMover() succeeded.

        allMovers.push_back(new_mover); 
    }

    //Other code
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...