Страницы

Слово о константах.

Каждый человек, который  создает клиент-серверные приложения, обязательно сталкивается с проблемой идентификации неких сущностей, событий и атрибутов единым для обеих сторон способом.
Передавать идентификаторы строками конечно крайне удобно и для разработки и для отладки ибо всегда можно глазами видеть всякое событие и какой атрибут куда полез. Но строки это всегда дополнительный размер исполняемого файла и строки обрабатываются (всяко дело) медленней целочисленных идентификаторов. И это особенно проявляется когда надо обрабатывать значительных размеров пакет событий. Значит целые числа.
Но система идентификации может быть сложной. Идентификаторы могут наследоваться, расширяться. Работать с #define можно, но муторно. Перечисления (те которые enum) не наследуются. (Всякие фокусы с LastValue не в счет. Не решение)
Значит надо делать иерархию наследования идентификаторов. Но проблема с небезопасными гарантированными пространствами наследуемых имен остается. За нумерацией надо следить. А не хочется, потому как человек склонен к лени и ошибкам. Значит приходится платить цену и использовать Uuid идентификаторы, которые при передаче занимают 16 байт и достаточно быстры для обработки. Да конечно 16 байт это не 4, но у всего есть цена. Зато их много и не будет повторений.
Определились. Сквозные идентификаторы будут UUID. Как их представить?
В виде #define определения?
В виде константы, помещенной в определенную область видимости?

Существует мнение грандов и учителей программирования на С++, что использовать #define - признак плохого тона. С этим трудно не согласиться.
С другой стороны практикующие знают (и даже я), что константные идентификаторы много занимают места в исполняемом коде.
Насколько много?
Мне довелось поставить эксперимент на (всего!!!) нескольких десятках UUID идентификаторах и сравнить сколько будет места занимать модуль при использовании констант и (пока скажем так) иначе.

Вариант 1 )
namespace Foo{
const QUuid Test("e75fa2be-288b-4b9a-9728-e94a7bde5504");
}
И таких много.

Вариант 2)
Создаем статическое хранилище неких типов (или коллекций).
Создаем для каждой коллекции структуру в которой определяем константы члены класса.
Создаем глобальное статическое хранилище экземпляров коллекций.

struct TestCollection
{
static QUuid TypeId;
static QUuid Test;
TestCollection() :
TypeId("ceb36014-1439-4562-b004-c99fc0529114"),
Test("56c1c04e-73df-46b8-a2fc-ff5a2fe922d0"){}
static TestCollection* instance();
};

Понятно, что instance регистрирует экземпляр один раз и потом выдает как указатель для необходимого использования.

Так вот о чем это я! Дело в том, что при первом варианте использования идентификатора и при втором размеры модуля весь значительно отличаются друг от друга. Я знал что константы любят размер, но я не думал что так.

В первом и во втором случае на одном и том же наборе констант разница в размерах составила 3 раза при сборке gcc и 6(!!!) раз при сборке llvm+clang.
Само собой совершенно ясно что мне гораздо интересней пихать в телефон модуль размеров в 400К а не 1.3М и не 2.4М.

Да и еще немного оптимизаций. Ясно, что UUID идентификаторы надо как-то вводить, что они хранятся в файле как строка и занимают аж 36 байт каждая. Много. Если мы встали на эти лыжи, деваться не куда. Однако, немного оптимизировать строку инициализации можно. Ее можно представить ---


QUuid SystemEvents::TypeId =QUuid::fromRfc4122(QByteArray::fromBase64("qlWDnk+ETdOb48N8INdiew"))


например вот так. 14 байт на каждый идентификатор на дороге не валяется.

Удачи всем!
Related Posts Plugin for WordPress, Blogger...