Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
Я видел код, который перегружает оператор '%' чтобы обозначить продукт с точкой
if(smth) {
doSmth();
} else if(smthElse) {
doSmthElse();
}
if(smth)
{
doSmth();
}
else if(smthElse)
{
doSmthElse();
}
foreach (item; list) process(item); if (b > c) d = c;else if (c > d) e = f;По итогам голосования на моём комментарии
общепринятое форматирование для конкретного языка форматирования
По итогам голосования на моём комментарии и карме можно видеть, что 2/3 людей любят переносить открывающую фигурную скобку, 1/3 не любит, и 1 человек ОЧЕНЬ не любит :)
Но это также и дело привычки — например, для моих глаз намного читабельнее текст с бОльшими вертикальными отступами Читать гораздо приятнее. Исключительно ИМХО.
которые читают код как книжку, и любят, чтобы он был «свёрстан» эстетично — со смысловыми разносами блоков

...split(..., const float epsilon, ...) только снижаю читабельность, потому как, подсознание нашептывает, что epsilog передается по ссылке, но не модифицируется, ан нет.А вообще, зачем это const float? Как будто float может измениться, странно смущает меня это почему-то.
финальный модификатор const после списка параметров — мой самый любимый. Он указывает на то, что idSurface::Split() не будет изменен самой поверхностью (surface).Небольшая неточность: не «не будет изменен самой поверхностью», а «не будет изменять саму поверхность».
За последние 6 недель разработки Dyad я дописал 13k строк кода.Вот это скорость! При стандартном 8-часовом рабочем дне получается примерно 1 строчка кода в минуту.
Одной из главных задач Clang является поддержка инкрементной компиляции, позволяющей более тесно интегрировать компилятор и графический интерфейс среды разработки, в отличие от GCC, который был создан для работы в классическом цикле «компиляция-линковка-отладка». В отличие от GCC, ориентированного преимущественно на кодогенерацию, Clang стремится предоставить универсальный фреймворк для парсинга, индексации, статического анализа и компиляции языков семейства Си. В частности, Clang не производит упрощений исходного кода на этапе парсинга (как это делает GCC), гарантируя точное воспроизведение исходного текста в AST.
class ClassType {
public:
const int var;
ClassType(int var) : var(var) {}
};
оригинал
int check_param_and_do_someting(int param)
{
if( param > 0 )
{
if( param % 3 == 0 )
{
//do something
return 0;
}else
{
return -2;
}
}else
{
return -1;
}
}
"ленивый" вариант:
int check_param_and_do_someting(int param)
{
if( param <= 0 )
{
return -1;
}
if( param % 3 != 0 )
{
return -2;
}
//do something
return 0;
}
int check_param_and_do_someting(int param)
{
if( param <= 0 ) return -1;
if( param % 3 != 0 ) return -2;
//do something
return 0;
}
/** Find all file or directory names matching a given pattern
in this archive.
@note
This method only returns filenames, you can also retrieve other
information using findFileInfo.
@param pattern The pattern to search for; wildcards (*) are allowed
@param recursive Whether all paths of the archive are searched (if the
archive has a concept of that)
@param dirs Set to true if you want the directories to be listed
instead of files
@return A list of filenames matching the criteria, all are fully qualified
*/
virtual StringVectorPtr find(const String& pattern, bool recursive = true,
bool dirs = false) = 0;
void renderSystem(RenderSystem* system);
void setRenderSystem(RenderSystem* system);
10) Собственно, не использовать перезагрузку операторов — тоже весьма странный совет. Перезагрузка operator() и operator= — это вообще фундамент C++.
inline Vector3& operator = ( const Vector3& rkVector )
{
x = rkVector.x;
y = rkVector.y;
z = rkVector.z;
return *this;
}
struct Coord{
double *CX;
Coord(){ CX=new double[2]; }
~Coord(){ delete CX; }
Coord(Coord const &p){
CX=new double[2];
CX[0]=p.CX[0]; CX[1]=p.CX[1];
}
Coord &operator=(Coord const &p){
printf("Coord::operator=(%p): %p\n",&p,this);
CX[0]=p.CX[0]; CX[1]=p.CX[1];
return *this;
}
};
struct Vector{
Coord X,Y,Z;
};
~Coord(){ delete [] CX; }
CX — массив из 2х элементов, а масивы, если память под них выделена с помощью operator new[] — соответственно и зачищаются с помощью operator delete[].double* CX = new double(0.5);
delete CX;
CX = NULL;
Vector3 operator*( const Vector3& rhs ) const;
и
double operator%( const Vector3& arg ) const { return X*arg.X+Y*arg.Y+Z*arg.Z; }
Vector3 operator* ( const Vector3& rhs) const
{
return Vector3(
x * rhs.x,
y * rhs.y,
z * rhs.z);
}
float dotProduct(const Vector3& vec) const
{
return x * vec.x + y * vec.y + z * vec.z;
}
Vector3 crossProduct( const Vector3& rkVector ) const
{
return Vector3(
y * rkVector.z - z * rkVector.y,
z * rkVector.x - x * rkVector.z,
x * rkVector.y - y * rkVector.x);
}
Без перегрузки эти операции станут менее очевидными и потребуют больше времени на написание и чтение. Здесь Doom и останавливается. Я видел код, которые идет дальше. Я видел код, который перегружает оператор '%' чтобы обозначить скалярное произведение векторов, или оператор Vector * Vector, который выполняет умножение векторов.
И они там немного не так сделали, они используют шаблоны для всяких утилитарных, низкоуровневых вещей, например для реализации контейнеров, но не используют их для реализации чего-то более сложного.
printf куда лучше читается, нежели stringstream
По поводу более хороших инструментов — printf, это часть nt.dll, он есть всегда, а вместе с «хорошими инструментами» придется притащить в проект половину boost-а. Современные компиляторы С++ умеют находить ошибки форматирования, также, есть safe версии printf, не способные переполнить буфер.
Под «безопасной версией printf» я имел ввиду snprintf, которая есть в glibc, которая знает размер переданного в нее буфера
А можно без менторского тона? Я начал использовать boost в 2006-м году и использую до сих пор :)
можно запросто раздуть размер своего исходника, который будет потом долго компилироваться и генерировать объектный файл разером в десятки мегабай
У буста действительно есть проблемы и не для всякого проекта он подходит. В game-dev обычно очень консервативно относятся к таким вещам и их можно понять.
Прекомпилированные заголовки — не всегда решают задачу.
Это вообще нельзя использовать, потому что оно кладет весь код в одну единицу трансляции
Лучше всего использовать boost::format.
Я мечтаю о том, чтобы все переменные в C++ по умолчанию были const
Я не говнокодю и за свой код мне не стыдно.
Код Doom 3 — это доработанный код Quake 3
During development, it was initially just a complete rewrite of the engine's renderer, while still retaining other subsystems, such as file access, and memory management. The decision to switch from C to the C++ programming language necessitated a restructuring and rewrite of the rest of the engine; today, while id Tech 4 contains code from id Tech 3, much of it has been rewritten
Это пустая трата строк кода и последующего времени на его чтение. Такой вариант съест больше вашего времени, чем...Код (любой) пишется для того, чтобы превратиться в ассемблерные команды, поэтому самое главное, во сколько команд он превратится и сколько процессорного времени будет потрачено при выполнении.
Сравните стоимость часа работы программиста, и часа процессорного времени — чтобы нелепость вашего утверждения стала очевидной.
Задали мне задание: рассчитать значения хитрой комбинаторной функции, и чем в большем числе точек, тем лучше. Функция такая, что время на её вычисление экспоненциально зависит от величины аргумента, т.е. «с наскоку» её не сосчитать.
Я сел и неделю писал прогу на VB с разными наворотами вроде возможности приостановки вычисления (типа Hibernate) и последующего продолжения; упаковки восьми булевских переменных в один байт; всяческой оптимизацией и т.п.
За 20 часов (три ночи) эта прога сосчитала мне значения до 250.
Я сел и переписал прогу на VC, уже без наворотов, а просто чтобы прикинуть скорость. Скорость была совершенно та же. Сейчас эта программа работает девятый час, и сосчитала значения до 140.
Я пошёл к преподу выяснять, как быть — получается, уже для 1000 потребуется месяц вычислений, а то и больше. И он мне показал свою прогу на JS для решения этой же задачи. Мои результаты до 250 она получает за несколько минут, за 20 часов — примерно до 400, а за пару суток — до 600. Естественно, у него там более хитроумный алгоритм, выгода от которого в тысячи раз превышает разницу в быстродействии языков.
noldo32, который призывал к противоположной крайности — выжиманию процессорных тактов любой ценойА где, спрашивается, я говорил про "любую цену"?
Если при прочих равных есть возможность напечатать высокоуровневые инструкции так, чтобы с т.з. ассемблера получилось легковеснее — надо делать именно так.(внимание: выделено жирным шрифтом)
Прикольный пример как простая конкатенация строк (казалось бы обычная конструкция языка) может существенно ударить по производительности.
/*
================
idAFEntity_WithAttachedHead::Restore
================
*/
void idAFEntity_WithAttachedHead::Restore( idRestoreGame *savefile ) {
head.Restore( savefile );
}
/*
================
idAFEntity_Base::DropAFs
The entity should have the following key/value pairs set:
"def_drop<type>AF" "af def"
"drop<type>Skin" "skin name"
To drop multiple articulated figures the following key/value pairs can be used:
"def_drop<type>AF*" "af def"
where * is an aribtrary string.
================
*/
void idAFEntity_Base::DropAFs( idEntity *ent, const char *type, idList<idEntity *> *list ) {
...
// get the initial origin and axis for each AF body
for ( i = 0; i < af->bodies.Num(); i++ ) {
fb = af->bodies[i];
...
финальный модификатор const после списка параметров — мой самый любимый. Он указывает на то, что idSurface::Split() не сможет изменить саму поверхность (surface). Это одна из моих самых любимых возможностей в С++, по которой я так скучаю в других языках. Она позволяет мне вытворять подобное:
void f(const idSurface &s) {
s.Split(....);
}
если Split не была бы определена как Split(...) const; этот код бы не скомпилировался. Теперь я всегда буду знать, что при любом вызове f() не изменит поверхность, даже если f() передается поверхности другой функцией или вызывает какой-либо из методов Surface::method().
Вы это будете знать на этапе компиляции, или блокирование изменения поверхности произойдет в рантайме?На этапе компиляции.
Исключительная красота исходного кода Doom 3