Comments 37
Обратите внимание, что цикл for не выполняет никакой работы, но изза вынесенной за пределы цикла переменной i у неё валидное значение 0. Выполняется апдейт только первого звука в массиве.
Разве? Цикл выполняет работу: неэффективно меняет i
с 0
на size
.
Так что последующее внецикловое sounds[i]
даёт sounds[size]
(UB), а не sounds[0]
.
Да, спасибо что поправили, так выглядит. Помню дебажил этот блок, он работал только в релизе, компилятор выкидывал оба цикла и оставлял только вызов первого элемента в итоге. Поправил описание
int i, size = sounds.size();
...
for(i = 0; i < size; ++i); {
sounds[i].pre_update(dt);
}
а почему этот цикл выкидывается?
Мы с коллегами так и не поняли, попытки поворошить код в этом месте или изменить флаги приводили к нормальной работе. Компилятор clang 7.0.19 для плойки. Но конкретно такой код работал с ошибками
хм, а разве он выкидывается? sounds[i].pre_update(dt);
исполнится же один раз.
Потому что цикл здесь - это вот эта часть: for(i = 0; i < size; ++i);
, а компилятор видит, что никаких сайд эффектов у неё нет. Может быть заменен на простое присваивание в i.
я так понял что выкидывается и "мнимое" тело цикла, которое после ";". Оно то выполнится один раз
Да, забавно, тест на внимательность не прошел. Интересно статик анализаторы на такое ругнутся ведь наверное...
Как ни странно, но лучше всего с ним бы справился банальный автоформаттер типа clang-format
, который на более-менее крупном проекте ИМХО обязательно должен быть.
Может быть заменен на простое присваивание в i.
Тогда опять же, было бы sounds[size]
, потому что i == size
, а автор утверждает, что выходило sounds[0]
. Как оно может выходить, я так и не понял. Для этого надо, чтобы for(i = 0
осталось, а ++i)
было выкинуто. Потому что без цикла i
вообще не инициализировано.
Майкрософт сначала просто морозились и реджектили билды, потом прислали комплайнс на забытые сенситив данные. Какие блин такие забытые?
Было же нормально, потом русский пошёл вразнос.
Большинство вышеперечисленных багов - это код, написанный на C в файлах .cpp. Почти все остальные - из-за выключенных предупреждений компиляторов.
Ну что поделать, люди так пишут. Если код решает поставленную задачу, заказчику обычно до лампочки на чем и как он написан, хоть на бейсике, se la vi. А вот когда он попадает к вам уже встаёт вопрос, поправить в рамках того что сделано или рисковать переписывать полждвижка с непонятными перспективах.
В геймдеве вообще принято тесты писать? Или девочки из отдела тестирования, протестирую?
Или геймеры на релизе?
void init(std::vector<TextureDX12> &a) { memset(a.data(), 0, sizeof(TextureDX12) * a.size());}
В этом куске кода даже C++11 нельзя использовать? Почему бы здесь не использовать for (auto& v... или std::fill?
Видимо, потому что класс TextureDX12 до виртуальности был оберткой над умным указателем. Хотя код не выглядит безопасным, потому что shared_ptr - не pod. И дизайн такой, что после случайного повторного вызова init память потечет. Если естественное начальное состояние nullptr, можно было в класс добавить инициализацию.
void Particle::CreateVerties(size_t p){ std::shared_ptr<Vertex> ss(new Point[p * 3]); // each p is 3 vertex ....}
Так тут each Point состоит из 3 Vertex или наоборот - each Vertex состоит из трёх Points?
Если каждый Vertex содержит 3 точки, разве недостаточно написать так?
auto ss = std::make_shared<Vertex[]>(p);
В C++ ключевое слово volatile не обеспечивает атомарность
Интересно, что до сих пор некоторые упорно с этим спорят.
Но что означает [volatile] в квадратных скобках?
Коллега ставил и убирал в этом месте volatile, и так закрывал баг. Несколько раз
Меня просто удивило, что слово volatile в квадратных скобках написано. Оно же без скобок пишется. Это же не [[nodiscard]] какой-нибудь.
Вероятно это связано с реализацией спинлоков и других примитивов, люди смотрят на код который там написан. Видят что везде используется волатайл переменные и как-то связывают это с мультитредом.
Возможно, это Майкрософт постарались, т.к. у них в компиляторе есть ms specific, в котором они зачем-то навесили acquire/release на volatile:
https://learn.microsoft.com/en-us/cpp/cpp/volatile-cpp?view=msvc-170
Ну, зачем как раз понятно.
Всегда было странно ставить отдельный барьер для компилятора, и отдельный - для процессора, гораздо лучше когда первый автоматически подразумевает второй. Другое дело, что нестандартные языковые расширения в 21м веке уже не кажутся чем-то хорошим.
странно ставить отдельный барьер для компилятора, и отдельный - для процессора, гораздо лучше когда первый автоматически подразумевает второй.
С одной стороны логично и удобно, да, а с другой:
нестандартные языковые расширения в 21м веке уже не кажутся чем-то хорошим.
Вот это ^ всё и портит. Сам видел виндовый код с volatile в качестве атомиков, про который авторы говорили: "А чо такова, работает жы!" А тот факт, что это ms specific и непортабельно по определению, как-то от них ускользает, потому что уже привыкли так писать. Тут плохо ещё и то, что этот конкретный ms specific включён по умолчанию для x86 и x86_64, и все начинают думать, что всё всегда будет работать.
Ну и в плюсах начиная с С++11 есть атомики, в которых можно ещё и задавать различные memory order.
bool ComponentVec::add(Component c) {
А здесь не лучше ли передавать Component по const-ссылке?
К задачке не относится, но расскажу почему там так. По бест практис конечно лучше передавать ссылку, но в конкретных случаях иногда жертвуют перфом, чтобы избавиться от необходимости синхронизации этого кода. Сам вектор компонентов потокобезопасный должен быть, и чтобы не городить лишних мьютексов передавали копию компонента, компонент в этом случае выступает аналогом shared_ptr, который хранит в себе нужные данные не опасаясь что какието из них повиснут. Както так, код не мой, просто баг затронул АИшку и пришлось разбираться
pair<vec, vec> * plane_egdes = alloca (16 * sizeof(vec) * 2);
Тут же ещё одна ошибка, потому что (теоретически) могут быть байты выравнивания внутри pair.
А ошибка здесь в том, что поиск в мапе компонентов производитя ТРИ раза в худшем случае, первый на find(c.id()), второй на insert() если компоненты нет. И третий в операторе доступа по индексу.
На самом деле ошибка здесь в использовании дерева вместо хеш-таблицы.

Ох.
По 0х13, ENSURE(secretKeyPwa[0] == 0);
всё ещё неправильно. Ваш memset
всё так же может быть выброшен по as-if-rule. Используйте memset_s
, для него не нужны никакие костыли, тем более не гарантированные стандартом.
Вы можете увидеть, что код с memset и без компилируется одинаково, если компилятор может доказать, что ваш массив с секретом не используется после memset.
Шеф, всё пропало