Pages

Monday, August 31, 2009

Как убрать виртуальную функцию, если нужно ускорить программу

Вот простая програмка, демонстрирующая использование полиморфизма:
#include <iostream>
using namespace std;
class A
{
public:
virtual void out() = 0;
};
class B : public A
{
int x;
public:
B() : x (12345) {}
void out()
{
cout << "object of class B. x = " << x << endl;
}
};

class C : public A
{
double x;
public:
C() : x (123.456789) {}
void out()
{
cout << "object of class C. x = " << x << endl;
}
};
int main()
{
A* p = new B;
p->out();
delete p;
p = new C;
p->out();
delete p;
return 0;
}

В таком простом случае использование виртульных функций оправдано. А что, если такую виртуальную функцию нужно было бы вызвать в цикле миллион раз?
for (int i=0; i < 1000000; i++) 
p->out();
Тело цикла имеет только одну строку - вызывается только одна функция. И если нужно такой код оптимизировать то что же тут делать?
Да хотя бы не тратить время на игру с полиморфизмом. Если знать, что в данный момент идет работа с объектом класса А, то и использовать класс А:
for (int i=0; i < 1000000; i++) 
reinterpret_cast<const T*>(p)->out();
Ну не так, конечно. Это, просто шутка. Вот так:
A* pA = reinterpret_cast<const T*>(p);
for (int i=0; i < 1000000; i++)
pA->out();
И в этом примере функцию out() нужно искать в таблице виртуальных методов.
Лучше всего, если уж говорить об ускорении программы, не использовать виртуальность. Например, классы из первой программы будут выглядеть так:
template <typename T>
class A
{
public:
void out()
{
reinterpret_cast<const T*>(this)->out();
}
};

class B : public A<B>
{
int x;
public:
B() : x (12345) {}

void out()
{
cout << "object of class B. x = " << x << endl;
}
};

class C : public A<C>
{
double x;
public:
C() : x (123.456789) {}
void out()
{
cout << "object of class C. x = " << x << endl;
}
};

Шаблон помогает ускорить программу. Конечно, приходится объявлять объекты используя шаблон. Виртуальность - это красиво, но медленно - во время выполнения программы определяется тип объекта, в таблице виртуальных методов находится поинтер на "актуальную" функцию, и так далее.
В случае, когда известно заранее с каким типом объекта из иерархии классов мы будем работать, можно "пожертвовать" красотой и ускорить программу используя шаблонное программирование.

Saturday, August 29, 2009

Destinator 9 на Сингапуре


Destinator 9 на телефонах LG GM730 появился на Сингапуре. Полный отчет об этом можно найте здесь

Еще о размерах объектов

Вот простая програмка:
#include <iostream>
using namespace std;

class A {};

class B
{
A a[2];
A b;
};

class C
{
A a;
A* b;
};

class D : public A
{
A* b;
};

int main()
{
A a;
B b;
C c;
D d;
cout << "sizeof A is " << sizeof(a) << endl;
cout << "sizeof B is " << sizeof(b) << endl;
cout << "sizeof C is " << sizeof(c) << endl;
cout << "sizeof D is " << sizeof(d) << endl;

return 0;
}

Вот что увидим на экране:

Все 4 объекта имеют "странный" размер?
Объект типа A имеет размер 1 байт. Класс A "пустой" - ни одного члена. Если бы разработчики стандарта допустили нулевой размер, то абсолютная чепуха вышла бы с классом B - тут объявлены два члена типа A. Если бы A имел размер 0, то и размер класса B тоже был бы 0. И что делать с массивом A a[2]? Как найти второй элемент в этом массиве? Какой у него размер? Легче договориться, что размер пустого класса равен 1 байту и все проблемы снимаются.
А класс B имеет размер 3. Казалось бы, что это объяснимо - класс B содержит 3 объекта типа A, а их размер 1, значит, B имеет размер 3 байта.
Но тогда почему объект типа C имеет размер 8?
Выравнивание - alignement. Добавились 3 байта (padding), чтобы размер объекта был кратным 8.
А вот объект класса D имеет размер 4. То есть память "ушла" только на поинтер. Наследование "съэкономило" 4 байта.

C++ стандарт: ну уж очень теоретический вопрос

Книги Маерса всегда слишком затериотеризированы. В том смысле, что эфективность его С++ делает дизайн красивым, но, зачастую, непонятным, "скрывающим" очень важные вещи, "мешающим" оптимизировать програмный код, лишающим возможности ускорить выполнение программы, а то и возможности быстро вносить в нее изменения.

Это, конечно, мое частное мнение.

Это в его книгах я нашел объяснение что такое скрытое наследование классов - private inheritance:
class A {};
class B : private A {}

Я даже пробовал использовать применять эти знания на практике. И практика показала, что нужно быть проще. Тогда и программа понятней. Например, практикующий програмист не ожидает увидеть частное наследование в комерческой програме. А в спешке, еще и будет сходить с ума - почему это public переменная недоступна? Как, например, здесь:
#include <iostream>
using namespace std;

class A
{
public:
int x;

A() : x(0) {};
};

class B : private A
{
public:
B() : A() { x = 1; };
};

int main()
{
A a;
B b;
cout << "A a.x = " << a.x << endl;;
cout << "B b::a.x = " << b.x << endl;
return 0;
}

Компилятор "говорит":
error C2247: 'A::x' not accessible because 'B' uses 'private' to inherit from 'A'

И, конечно, Скотт Маерс показывает как это можно "победить":
#include <iostream>
using namespace std;

class A
{
public:
int x;

A() : x(0) {};
};

class B : private A
{
public:
using A::x;
B() : A() { x = 1; };
};

int main()
{
A a;
cout << "A a.x = " << a.x << endl;;

B b;
cout << "B b::a.x = " << b.x << endl;

B* pB = new B;
pB->x = 2;
cout << "B* pB->x = " << pB->x << endl;
delete pB;

return 0;
}

Я не знаю зачем это нужно. Но это существует. Кто знает, может и прогодится когда-нибудь.

Wednesday, August 5, 2009

Чтобы не забывать

Я вот все время забываю эти простые формулы.
 #include <iostream>
using namespace std;
bool is_even_number(int n)
{
return ((n + 1) & 1);
}
bool is_odd_number(int n)
{
return (n & 1);
}
int nearest_smaller_2(int n)
{
return (n & ~1);
}
int nearest_2(int n)
{
return ((n + 1) & ~1);
}
int nearest_4(int n)
{
return ((n + 3) & ~3);
}
int nearest_8(int n)
{
return (((n - 1) / 7) << 3) + 8;
}
int main()
{
for (int i = 0; i < 33; i++)
{
cout << i << " " << is_even_number(i) << " " << is_odd_number(i);
cout << " " << nearest_smaller_2(i);
cout << " " << nearest_2(i);
cout << " " << nearest_4(i) << " " << nearest_8(i) << endl;
}
return 0;
}

unsigned int ui16To32(unsigned short a, unsigned short b) 
{
return ((a << 16) | b);
}

unsigned short ui6To16(unsigned char a, unsigned char b)
{
return ((a << 8) | b);
}
А бывает нужно, особенно, если расчитывается сколько выделять памяти
Интересные алгоритмы с использованием битовых операций можно найти здесь:
http://www.coranac.com/documents/bittrick/
Математика для чисел с фиксированной точкой здесь:
http://www.coranac.com/tonc/text/fixed.htm
Системы исчисления и битовые операции здесь:
http://www.coranac.com/tonc/text/numbers.htm

Фотокамеры-телефоны, фотокамеры-прожекторы,...

Фотокамера стала обязательным атрибутом мобильных телефонов. Качество этих камер все время улучшается - мой HTC c 3 мегапиксельной камерой иногда даже делает неплохие снимки. LG с 5 мегапикселами и 10 уже в дороге на рынок, Nokia - 8 и обещают 12, некоторые модели Samsung уже и выглядят больше как фотокамеры, чем телефоны, ..., iPhone....

А что же производителям "мыльниц" делать?

Есть идеи. Например, фотокамеру и проэктор "в одном флаконе":


Фотокамеру и телефон:


У меня такая идея вызывала смех. Ну не смех, так улыбку. Наш Nikon с телефоном внутри. Это где ж его прицепить? Объектив мешать будет такой "телефон" к уху приложить. Ну это не мыльница. А видите на картинке, что произошло? Фотокамера внешне стала выглядеть как телефон. Но камера здесь "главная". Может быть даже поддержка HDMI?
Менеджеру даже в примитивной мобилке нужен доступ к майлу и календарю. Программист без нормального интернет браузера телефон не возьмет. Ну а фотограф не назовет фотокамерой то, что есть в телефоне. Наверное, такие фотокамеры предназначены, в первую очередь, для фанатов фотографии.

Что еще для фотокамеры можна придумать? Правильно - добавить GPS и автоматически добавлять адрессную информацию к снимкам. Только не такую дурную, как на картинке внизу - что с этими градусами и минутами делать?

Sunday, August 2, 2009

Nikon объявила о выпуске самой простой зеркальной фотокамеры

Компания Nikon выпустила сразу две новинки..Первая новинка - камера начального уровня D3000. Вторая - это апгрейд известной модели D300, D300s. Она получила все достоинства своей предшественницы плюс несколько значимых нововведений.
Камера D3000 позиционируется создателями как самое простое в эксплуатации решение такого рода (а это цифрозеркалка с поддержкой DX). «Фишкой» модели является специальный режим, помогающий путем специальных вопросов подобрать подходящие настройки под требуемый снимок.
Модель оборудована 10,2-мегапиксельным CCS-сенсором с чувствительность от 100 до 1600 ISO. Также тут имеется двойная система очистки матрицы от пыли, TFT-дисплей диагональю 3'', автофокус с 11 точками, серийная съемка скорость 3 снимка в секунду, зеркальный прямой видоискатель с пентазеркалом. Стоит отметить, что на камере применен байонет Nikon F с контактами АФ.