Comments 28
А Вы сообщили разработчикам о найденных ошибках?
Под спойлером в конце есть ссылка с ответом на ваш вопрос. Или вы тролите? :-)
Когда будет версия для FreeBSD?
Какую версию кокоса вы проверяли, как я понимаю 3.x? Ее относительно недавно переписывали с нуля с учетом C++11, по сравнению с 2.x там все и должно быть хорошо. До 3.x, cocos2d-x представлял собой стремную смесь С, С++ с очень сильным влиянием Obj-C API, например, в управлении памятью.
Какую версию кокоса вы проверяли, как я понимаю 3.x? Ее относительно недавно переписывали с нуля с учетом C++11, по сравнению с 2.x там все и должно быть хорошо. До 3.x, cocos2d-x представлял собой стремную смесь С, С++ с очень сильным влиянием Obj-C API, например, в управлении памятью.
Напишите нам от имени компании и мы обсудим варианты сотрудничества. Мы можем заключить контракт на аудит вашего кода или интеграцию PVS-Studio в процесс разработки (адаптацию для FreeBSD и т.д.). Никаких публичных версий. Только контрактные работы.
Ссылка с исходниками приведена в самом начале статьи. Каталог, взятый там, называется у меня cocos2d-x-3. Как видите, не всё ещё переписали. Но в целом да, тут всё хорошо. Но опять же, я не их разработчик и мог что-то упустить.
более правильным будет использование оператора 'new':Копи-паст детектед;) правильно будет
_pointVertexes = new Vec2[sizeof(Vec2) * _maxPoints]; _vertices = new Vec2[sizeof(Vec2) * _maxPoints * 2];
_pointVertexes = new Vec2[_maxPoints];
_vertices = new Vec2[_maxPoints * 2];
Если именно так задумано и ошибки нет, то код всё равно лучше изменить. Можно воспользоваться оператором 'break'.
А как может быть задумано еще? Очевидно, что если цикл вида do {…} while(false), то он в любом случае может быть выполнен только один раз и используется вместо goto при ошибках. Довольно логично, если рассматривать со стороны смысловой нагрузки, что используется continue, но не логично со стороны стандартного выхода из цикла :)
Они будут «инициализированы» далее пачкой. Зачем вызывать конструктор для 1000 элементов(который установит переменные в 0), если можно просто просто мемсетом(как пример) всё зачистить за 1 проход.
Зачем тогда Си++?
Там, где с ним удобнее. А игровой движок — такая штука, где микрооптимизации всюду. Если авторы на 100% знают, что конкретно для этих кусков памяти не нужна инициализация — то зачем её делать?
Зачем тогда Си++?
Чтоб не плодить сущности.
Если нам нужно поработать с 2х-мерным вектором — используем класс Vec2 по назначению.
Если нам нужно создать буффер вершин, которые (99% вероятности) просто будут отправлены далее в видеопамять — то почему бы не использовать уже существующую структуру данных?
П.С. У гейм-девелоперов другие задачи и заботы, здесь правила идеального мира не всегда подходят :)
Смотря с какой точки зрения рассматривать предупреждения как ложные. То, что некотоыре из приведённых примеров являются рабочими, и так и задумывались — не спорю, но статья(и анализатор) обращает на них внимание, потому что не совсем хорошо так писать. Потому что это не всегда очевидно, и не всегда понятно что же задумывалось на самом деле. И если какой-либо другой разработчик придёт исправлять что-то в таком коде( а в статьях говорится об Open Source) он может потратить гораздо больше времени и сил, или вообще получить в итоге что-то в духе Heartbleed.
Кстати, соглашусь. malloc() как раз и существует для случаев, когда нужно выделить неинициализированную память. Теоретически всегда можно было бы применять calloc(), который заполняет память нулевыми байтами, но порой это неэффективно и не нужно. Инициализация будет следовать далее. Да, это не слишком c++-style, чревато последствиями, и, вероятно, не даёт большого прироста в производительности, но такой код имеет право жить.
Мемсетом? А мемесет вам таблицу виртуальных функций в класс положит? А если в обьекте есть более сложные атрибуты чем поля с числами? Другие объекты и указатели например. Вырвать кусок памяти и потом забить нулями — это мягко говоря не самый универсальный подход, я бы даже сказал узкоспециализированый. Хотя по производительности может и быстрее (надо на досуге замер провести).
Что за странная привычка в чужой огород со своим уставом ходить? Если типичный программист на Java не имеет представления о том как устроены объекты, с которым он работает, то это вовсе не значит, что программисты на других языках устроены так же.
По производительности сильно быстрее, а что про всякие атрибуты и виртуальные таблицы — ну так на то C++ и низкоуровневый язык. В нём даже есть понятие POD, которое на уровне стандарта отделяет структуры, которые можно memset'ить от тех, которые нельзя (строго говоря POD можно копировать с помощью memcpy, а memset'ить нельзя, но эти гарантии дают другие стандарты).
По производительности сильно быстрее, а что про всякие атрибуты и виртуальные таблицы — ну так на то C++ и низкоуровневый язык. В нём даже есть понятие POD, которое на уровне стандарта отделяет структуры, которые можно memset'ить от тех, которые нельзя (строго говоря POD можно копировать с помощью memcpy, а memset'ить нельзя, но эти гарантии дают другие стандарты).
Провел замер (так чисто ради интереса), и так при memset'е выигрыш есть всегда, но ощутим лиш на больших массивах данных.
Тестовая структура:
struct Vector3D
{
private:
float x, y, z;
public:
Vector3D():x(0),y(0),z(0){;}
};
И так на моей машине массив из 1000000(!) обьектов был создан через new[] за 11-12 миллисекунд. С мемсетом 4-5 миллисекуд. В ограниченом ряде случаев такой подход имеет смысл.
Тестовая структура:
struct Vector3D
{
private:
float x, y, z;
public:
Vector3D():x(0),y(0),z(0){;}
};
И так на моей машине массив из 1000000(!) обьектов был создан через new[] за 11-12 миллисекунд. С мемсетом 4-5 миллисекуд. В ограниченом ряде случаев такой подход имеет смысл.
хм. в третьей все же не все так страшно оказалось. отполировали-таки. Было бы интересно еще интересно последнюю стабильную 2.7.x версию посмотреть, но она уже заморожена.
Как я уже сказал в самом начале, Cocos2d-x содержит довольно мало подозрительных мест. Проект сравнительно молодой и инновационный, не содержит унаследованного от старых времён кода. Наверняка разработчики используют различные способы контроля качества и стараются следовать современным стандартам, и методологиям программирования.
А тут вы не угадали. Проект родился из Cocos2d, написанном на Obj-C, почти 4 года назад. До третей, текущей, версии там было полно паттернов из мира Obj-C. На настоящие плюсы начали переписывать только в третей версии. И всё равно встречается рудиментарный код.
Статическими анализаторами они вообще не пользуются — конкретно задавал этот вопрос разработчикам. И вообще, сложилось впечатление, что о таком виде контроля качества они слышат впервые (заодно порекламировал PVS-Studio и CppCat). А вопрос такой у меня возник потому, что недавний билд не собирался на 64-битных системах по причине того, что в описании функции возвращаемый тип был указан как ssize_t, а в определении — как long int.
В общем, печально там всё. Особенно для тех, кому пришлось во внутренности фреймворка лезть.
php я на днях проверял, но статья может быть не раньше, чем через 2 недели, может даже общая про все языки.
Sign up to leave a comment.
Проверка кроссплатформенного фреймворка Cocos2d-x