Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.91/11: Рейтинг темы: голосов - 11, средняя оценка - 4.91
1 / 1 / 0
Регистрация: 21.11.2017
Сообщений: 24

Работа с std::vector содержащим указатели

21.11.2017, 12:27. Показов 2538. Ответов 49
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Привет! Я долгое время находился в ридонли, решил всё же задать вопрос, так как проблему не получается решить самостоятельно, из-за нехватки знаний по всей видимости. Оговорюсь, что на момент как я решил выучить c++, я уже хорошо знал несколько языков в том числе python java php и так далее.

Пишу небольшую игру на С++, кодовая база получилась уже сейчас довольно большая (для меня как только-только изучающего с++). Всё бы хорошо кроме одного момента.

В программе есть вектор содержащий все сущности игры вида:
C++
1
std::vector<Entity *> items
То есть любой объект наследует в конечном счёте Entity. Рендеринг каждого фрейма происходит путём обхода всех сущностей
и вызова у каждой из них ->update(), всё в принципе стандартно. Всё работает хорошо и как нужно кроме одного момента:

Периодически абсолютно в неясные для меня моменты (то есть какой либо зависимости у этих событий нет) получаю segfault либо на ->update(); (если я компилирую в g++) либо на сортировке объектов, в случае добавления новых сущностей для сохранения порядка отрисовки (если компилирую в msvc). segfault вызванный тем, что я пытаюсь вызвать метод объекта из вектора, при том что указатель ссылается на чистую область памяти (то есть объекта там уже нет)

Разработку веду в clion (gcс + mingw) И периодами сверяюсь с msvc (там удобный профайлер, да и в целом компилятор по умолчанию более строгий).

Понятно что весь код внутри update, я физически привести не смогу, вопрос вот в чем, может быть есть какие-то методики для понимания кто и в каком месте заменяет на heap'e реальные объекты таким образом, что указатель ведёт на чистую область памяти где не содержится изначально искомого объекта? Либо же я просто совершаю некую распространенную ошибку новичка и каким-то не правильным образом работаю с вектором таким образом что при наступлении определенных событий происходит segfault? Сразу оговорюсь, resize() у вектора я сам не вызываю, то есть аллокация новых элементов происходит автоматом и происходит успешно до какого-то момента.

Так же я могу привести кусок кода на котором возникает (в случае неопределенных обстоятельств) segfault при gcc компиляции.

C++
1
2
3
4
5
6
7
8
9
10
void sort() {
        std::sort(items.begin(), items.end(), [](Entity *a, Entity *b) -> bool {
            if (a->getDrawOrder() == b->getDrawOrder()) {
                return a->getDrawOrder() + a->getWorldCoordinates().x + a->getWorldCoordinates().y <
                       b->getDrawOrder() + b->getWorldCoordinates().x + b->getWorldCoordinates().y;
            } else {
                return a->getDrawOrder() < b->getDrawOrder();
            }
        });
    }
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
21.11.2017, 12:27
Ответы с готовыми решениями:

На основе исходного std::vector<std::string> содержащего числа, создать std::vector<int> с этими же числами
подскажите есть вот такая задача. Есть список . Создать второй список, в котором будут все эти же числа, но не в виде строк, а в виде...

Как передать целочисленную матрицу типа std::vector<std::vector<int> > в функцию?
Здравствуйте. Почитал на форуме, но так и не понял что я делаю не так. Имеется двумерный вектор. Размера .. Нужно его передать в...

Вывести значения std::vector<std::vector<int*> >
Подскажите, как вывести значения? const size_t row = 3; const size_t col = 3; std::vector&lt;std::vector&lt;int*&gt; &gt; imatrix; ...

49
77 / 50 / 16
Регистрация: 17.05.2015
Сообщений: 262
22.11.2017, 16:25
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от mrAndersen7 Посмотреть сообщение
int startSize = items.size(); for (int i = 0; i < startSize; ++i) { Entity *e = items[i]; e->update(); } int endSize = items.size();
сделай так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
int startSize = items.size(); //если эта пермеенная не используется вне цикла, то лучше item.size() перенести в цикл. Спасет от в случае, если после update вектор уменьшиться.
 
        for (int i = 0; i < startSize; ++i) {
            Entity *e = items.at(i); //метод at выдаст исключение, в случае выхода за предел массива.
            if (e == nullptr)
                /*exceprion invalid pointer */
            else 
                e->update();
            startSize = items.size(); //если при вызове update - количество айтемов изменится - это спасет от выхода из за предел массива
        }
 
        int endSize = items.size();
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if (!itemsToRemove.empty()) {
    for (auto &e : itemsToRemove) { //не люблю auto юзать в таких ситуациях. некоторые IDE не всегда понимают, что под auto 
        //remove if item presents in group
        if (e->getGroupName() != "~") { 
            removeFromGroup(e->getGroupName(), e); 
        }
        //remove from actual vector
        items.erase(std::remove(items.begin(), items.end(), e), items.end()); //я бы юзал не вектор, а std::list. что бы не вызывался по сто раз realloc 
        //free object
        delete e; //ты удалил обьект по данному указателю. Но сам указатель то еще жив)
        e = nullptr; //сделаем указатель нулевым, это упростит отладку!
      
    }
    itemsToRemove.clear();
}
А теперь после удаления обьекта, указатель на него обнуляется. Теперь введи проверки, перед выводом указателя
0
1 / 1 / 0
Регистрация: 21.11.2017
Сообщений: 24
22.11.2017, 17:34  [ТС]
Valeryn, проблема сейчас только в сортировке, причем только в gcc+mingw в msvc нет такой проблемы. С update разобрался
0
77 / 50 / 16
Регистрация: 17.05.2015
Сообщений: 262
22.11.2017, 17:51
Цитата Сообщение от mrAndersen7 Посмотреть сообщение
Valeryn, проблема сейчас только в сортировке, причем только в gcc+mingw в msvc нет такой проблемы. С update разобрался
А по какому критерию ты сортируешь контейнер УКАЗАТЕЛЕЙ?) и зачем ты его сортируешь?)

Добавлено через 8 минут
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void sort() {
        std::sort(items.begin(), items.end(), [](Entity *a, Entity *b) /*-> bool тут это не обзятельно*/ {
            if (a == nullptr)//если укатель нулевой - игнорируем (хотя тут лучше экзепшен прописать, он не должен быть нуливым!!!!!)
                return false; //нуливой указатель идет в конец
            if (b == nullptr)
                return true //нуливой указатель идет в конец.
            if (a->getDrawOrder() == b->getDrawOrder()) {
                //сложные конструкции обромляй скобками, а то запутаться можно
                return (a->getDrawOrder() + a->getWorldCoordinates().x + a->getWorldCoordinates().y) <
                       (b->getDrawOrder() + b->getWorldCoordinates().x + b->getWorldCoordinates().y);
            } else {
                return a->getDrawOrder() < b->getDrawOrder();
            }
        });
    }
СМОТРИ. Если ты сделаешь обнуление указателей при удалении, как я сказал выше, то при сортировке, элементы с нуливым указателем автоматически будут идти в конец. Хотя по хорошему, если указатель нуливой - вызывай экзепшен (ошибку) видимо у тебя из контейнера не удаляется указатель.

Добавлено через 4 минуты
Цитата Сообщение от mrAndersen7 Посмотреть сообщение
ричем только в gcc+mingw в msvc нет такой проблемы
А ты уверен что нет? Это называется не определенное поведение.
C++
1
2
3
4
5
6
7
8
9
10
11
12
class A
{
public:
   A(){}
   int a;
}
 
int main()
{
   A *a = nullptr;
   std::cout << a->a;
}
в mvs этот код работает. В gcc выдаст ошибку.
0
1 / 1 / 0
Регистрация: 21.11.2017
Сообщений: 24
22.11.2017, 18:06  [ТС]
СМОТРИ. Если ты сделаешь обнуление указателей при удалении, как я сказал выше, то при сортировке, элементы с нуливым указателем автоматически будут идти в конец. Хотя по хорошему, если указатель нуливой - вызывай экзепшен (ошибку) видимо у тебя из контейнера не удаляется указатель.
Но проблема присутствует только при сортировке. Во время обхоба всё цело - все указатели на месте да и в дебагере всё чисто
0
77 / 50 / 16
Регистрация: 17.05.2015
Сообщений: 262
22.11.2017, 19:06
Ты уверен, что указатели целы? Откуда такая уверенность? Дебагер не знает, удален обьект или нет. Он видит указатель на область памяти.
Сделай как я говорю. Обнуляй указатели во время удаления и проверяй их, перед каждым вызовом. Либо возьми или сам реализуй смартпоинтер, который это автоматически делает.

Добавлено через 20 минут
За место вектора используй лист.
Все равно ты перебираешь контейнер последовательно. А в ставка и удаление в листе дешевле будет. У листа свой собственный метод remove. Либо переопредели операторы <=> и суй обьекты в мап, если важна сортировка.

Добавлено через 15 минут
В базовом классе определи флаг isRemove.
Если он true - удаляй обьект.
А не плоди контейнеры. Так ты сможешь за одну итерацию перебора удалить обьекты и выполнить update
0
1 / 1 / 0
Регистрация: 21.11.2017
Сообщений: 24
23.11.2017, 00:15  [ТС]
Сделал всё вышесказанное, всё равно на сортировке segfault и только в gcc. Если убрать сортировку, проблема пропадает, всё равботает как надо
0
зомбяк
 Аватар для TRam_
1585 / 1219 / 345
Регистрация: 14.05.2017
Сообщений: 3,940
23.11.2017, 00:51
Можно попробовать сортировку через древнюю qsort:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int comparEntity(const void* v_a, const void* v_b)
{
    const Entity *a = *(static_cast<const Entity * const *>(v_a));
    const Entity *b = *(static_cast<const Entity * const *>(v_b));
 
    if (a->getDrawOrder() == b->getDrawOrder())
    {
        return (a->getDrawOrder() + a->getWorldCoordinates().x + a->getWorldCoordinates().y) <
               (b->getDrawOrder() + b->getWorldCoordinates().x + b->getWorldCoordinates().y);
    } else
        return a->getDrawOrder() < b->getDrawOrder();
}
 
void sort() {
    if(items.empty())
        return;
    
    qsort(items.data(), items.size(), sizeof(Entity *), comparEntity);
}
Если в ней всё будет то ж самое, значит дело в чём-то другом.
0
1 / 1 / 0
Регистрация: 21.11.2017
Сообщений: 24
23.11.2017, 01:00  [ТС]
Цитата Сообщение от TRam_ Посмотреть сообщение
Можно попробовать сортировку через древнюю qsort:
Переделал на qsort - работает без проблем, правда медленнее (но это уже вопрос второй)
Что это за дичь?
0
зомбяк
 Аватар для TRam_
1585 / 1219 / 345
Регистрация: 14.05.2017
Сообщений: 3,940
23.11.2017, 01:23
Возможно какой-то прикол из-за конфликта перемещающих конструкторов С++14 с указателями. Теоретически должна помочь обёртка указателя в класс.

Добавлено через 6 минут
или попробовать другую версию компилятора
0
77 / 50 / 16
Регистрация: 17.05.2015
Сообщений: 262
23.11.2017, 09:50
Цитата Сообщение от TRam_ Посмотреть сообщение
Возможно какой-то прикол из-за конфликта перемещающих конструкторов С++14 с указателями. Теоретически должна помочь обёртка указателя в класс.
так он же оперирует не обьектами, а указателями. Или там где то перемещение/копирование самого обьекта происходит? А то я его весь код не видел.

Но вообще, архитектура программы в целом не очень хорошая.
Как я сказал - за место контейнера с удаляемыми объектами - можно хранить состояние обьекта и это состояние проверять при переборе.
За место вектора - лист и тем самым, нам не надо юзать erase. В добавок у листа инсерт в середину по итератору мгновенный. Да и вообще, за место сортировки можно с конца перебирать лист и вставлять новый обьект в нужную позицию по условию. Тогда у тебя контейнер почти всегда отсортированный будет.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
23.11.2017, 09:50
Помогаю со студенческими работами здесь

Как изменять размер std::vector<std::vector>?
Здравствуйте, как нужно изменять размер std::vector&lt;std::vector&gt; например: std::vector&lt;std::vector&lt;float&gt;&gt; data; ...

Std::vector<std::pair<std::vector<int>::iterator, std::vector<int>::iterator>
Вопрос по вектору. Допустим есть вектор, std::vector&lt;int&gt; vec; на каком - то этапе заполнения я ставлю закладку итератора, ...

Std::vector/QVector в классе или std::vector/QVector классов?
Доброе время суток! Собственно вопрос в самой теме, есть некий класс class WorkJornal { private: string manager; ...

Реализация класса MyString. Стандартная библиотека, std::string, std::vector
как добавить реализацию конкатенации строк через перегрузку оператора &quot;+=&quot; в классе MyString и почему ошибка выдается???#include...

Передача функции указатель на элемент std::vector<std::string>
Доброй ночи тем, кому не спится (или живет в другом часовом поясе:p)! Есть функция, требующая в качестве параметра указатель на...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
50
Ответ Создать тему
Новые блоги и статьи
Очистка реквизитов документа при копировании
Maks 09.04.2026
Алгоритм из решения ниже применим как для типовых, так и для нетиповых документов на самых различных конфигурациях. Задача: при копировании документа очищать определенные реквизиты и табличную. . .
модель ЗдравоСохранения 8. Подготовка к разному выполнению заданий
anaschu 08.04.2026
https:/ / github. com/ shumilovas/ med2. git main ветка * содержимое блока дэлэй из старой модели теперь внутри зайца новой модели 8ATzM_2aurI
Блокировка документа от изменений, если он открыт у другого пользователя
Maks 08.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа, разработанного в конфигурации КА2. Задача: запретить редактирование документа, если он открыт у другого пользователя. / / . . .
Система безопасности+живучести для сервера-слоя интернета (сети). Двойная привязка.
Hrethgir 08.04.2026
Далее были размышления о системе безопасности. Сообщения с наклонным текстом - мои. А как нам будет можно проверить, что ссылка наша, а не подделана хулиганами, которая выбросит на другую ветку и. . .
Модель ЗдрввоСохранения 7: больше работников, больше ресурсов.
anaschu 08.04.2026
работников и заданий может быть сколько угодно, но настроено всё так, что используется пока что только 20% kYBz3eJf3jQ
Дальние перспективы сервера - слоя сети с космологическим дизайном интефейса карты и логики.
Hrethgir 07.04.2026
Дальнейшее ближайшее планирование вывело к размышлениям над дальними перспективами. И вот тут может быть даже будут нужны оценки специалистов, так как в дальних перспективах всё может очень сильно. . .
Горе от ума
kumehtar 07.04.2026
Эта мне ментальная установка, что вот прямо сейчас, мол, мне для полного счастья не хватает (нужное вписать), и когда я этого достигну - тогда и полный кайф. Одна из самых сильных ловушек на пути. . . .
Использование значений реквизитов справочника в документе, с определенными условиями и правами
Maks 07.04.2026
1. Контроль срока действия договора Алгоритм из решения ниже реализован на примере нетипового документа "ЗаявкаНаРаботу", разработанного в конфигурации КА2. Задача: уведомлять пользователя, если. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru