#truestory #cpp #jobbing
Ну а теперь история, ради которой этот канал был создан, и она про отладку сторонних библиотек.
Мы используем boost. Но мало того, что мы используем boost, мы используем старый boost, а именно версии 1.62, потому что он поставляется с Astra Linux 1.6. А Астра наша приоритетная целевая ОСь. (На самом деле под виндой у нас boost v1.64, но сути это не меняет)
И вот затащили мы некоторое время назад open-license-manager, в составе которого библиотека licensecc и генератор лицензий lccgen. И вот последний тоже зависит от boost'а. Ограничений на версию в CMakeLists.txt не установлено, а в документации проекта сказано использовать >= 1.57, и с нашей старой версией (напомню, что это 1.62) оно в принципе собирается, но только если отключить сборку тестов, но кому эти тесты нужны, правда?
Однако, при запуске, падает во время разбора аргументов командной строки (используется boost::program_options). Опытным путём выяснили, что если подкинуть версию boost'а 1.71, то падения пропадают. Кажется, даже тесты собираются, но это не точно, они же нинужны, поэтому я не перепроверял.
В принципе, мы генератор лицензий заказчикам не отдаём, поэтому собрали это дело только под окошками с новым boost'ом, забив на сертификацию, и всё бы ничего, но вот теперь потребовалось заиметь генератор и под Астру...
Ну а теперь история, ради которой этот канал был создан, и она про отладку сторонних библиотек.
Мы используем boost. Но мало того, что мы используем boost, мы используем старый boost, а именно версии 1.62, потому что он поставляется с Astra Linux 1.6. А Астра наша приоритетная целевая ОСь. (На самом деле под виндой у нас boost v1.64, но сути это не меняет)
И вот затащили мы некоторое время назад open-license-manager, в составе которого библиотека licensecc и генератор лицензий lccgen. И вот последний тоже зависит от boost'а. Ограничений на версию в CMakeLists.txt не установлено, а в документации проекта сказано использовать >= 1.57, и с нашей старой версией (напомню, что это 1.62) оно в принципе собирается, но только если отключить сборку тестов, но кому эти тесты нужны, правда?
Однако, при запуске, падает во время разбора аргументов командной строки (используется boost::program_options). Опытным путём выяснили, что если подкинуть версию boost'а 1.71, то падения пропадают. Кажется, даже тесты собираются, но это не точно, они же нинужны, поэтому я не перепроверял.
В принципе, мы генератор лицензий заказчикам не отдаём, поэтому собрали это дело только под окошками с новым boost'ом, забив на сертификацию, и всё бы ничего, но вот теперь потребовалось заиметь генератор и под Астру...
Сейчас я вам расскажу про одну интересную оптимизацию. Нашёл её не я, а мой коллега, но интересной от этого она быть не перестаёт.
#jobbing #cpp #prog
Итак, имелся примерно следующий код на С++:
И этот код работал медленно. Даже нет, он работал оооооочень медленно. И мы уверены, что проблема именно тут, на эту функцию показали все анализаторы и профилировщики.
Коллега ускорил это дело примерно в 1000 (sic!) раз, удалив одну строчку.
Угадаете какую?
Правильный ответ будет в следующем посте с объяснением, почему так произошло :)
#jobbing #cpp #prog
Итак, имелся примерно следующий код на С++:
struct MyType;
using std::vector<MyType> = MyVec;
MyVec storage;
void foo(MyVec& new_elements) {
auto new_capacity = storage.size() + new_elements.size();
storage.reserve(new_capacity);
for (const auto& elem : new_elements) {
// do something with elem
storage.push_back(elem);
}
}
И этот код работал медленно. Даже нет, он работал оооооочень медленно. И мы уверены, что проблема именно тут, на эту функцию показали все анализаторы и профилировщики.
Коллега ускорил это дело примерно в 1000 (sic!) раз, удалив одну строчку.
Угадаете какую?
Правильный ответ будет в следующем посте с объяснением, почему так произошло :)
💩1
Преамбула: я начинал эту заметку ещё несколько месяцев назад, но не дописал совсем чуть-чуть в конце. Сейчас вот наткнулся снова и решил дописать. Всё, что ниже - это текст от "прошлого меня", за исключением последних трёх абзацев.
--------------------
У меня бомбит, поэтому сейчас будет эмоциональная история про пргрмвне (история про пргрмрвне на канале про пргрмрвне!)
#jobbing #prog #cpp #hate
Язык С++ довольно странный предмет, он вроде бы есть, но лучше бы его не было . Два С++-разработчика спокойно могут "говорить" на совершенно разных диалектах, в зависимости от того, какому стандарту они отдают предпочтение. При этом многим кажется, что если они хорошо знают один "диалект", то легко и спокойно перейдут на другой, более новый. Так вот, это не совсем так.
Начиная с С++11 существует такая интересная штука, как
Если в двух словах, то это хреновина, которая позволяет использовать ссылки так, как обычно их использовать нельзя.
Например: класть в
Зачем вообще это нужно? Чтобы избегать ненужного копирования, как минимум.
Например, очень удобно написать что-то такое:
Тем самым мы можем обработать обработать кучу данных из разных источников без необходимости их копирования; накладные расходы будут только на внутряночку
И всё было бы хорошо, если бы оно было хорошо, но, к сожалению, оно не хорошо.
Видя, какое удобство и магию предоставляет этот
Вот буквально сегодня я увидел примерно вот такое:
И всё, пиздец котёнку. Успело попасть в релизную ветку, благо на тестировании стали ловить странные падения.
Как программист вообще мог такое написать и так облажаться? Очень просто: это было два программиста.
Первый - внедрил использование
--------------------
У меня бомбит, поэтому сейчас будет эмоциональная история про пргрмвне
#jobbing #prog #cpp #hate
Язык С++ довольно странный предмет, он вроде бы есть
Начиная с С++11 существует такая интересная штука, как
std::reference_wrapper
.Если в двух словах, то это хреновина, которая позволяет использовать ссылки так, как обычно их использовать нельзя.
Например: класть в
std::vector
, или переприсваивать именно "значения ссылок", а не "значения куда указывают ссылки" (актуально для шаблонных алгоритмов).Зачем вообще это нужно? Чтобы избегать ненужного копирования, как минимум.
Например, очень удобно написать что-то такое:
struct Some {
Some() = default;
~Some() = default;
Some(const Some&) = delete;
Some(Some&&) = delete;
Some& operator=(const Some&) = delete;
Some& operator=(Some&&) = delete;
};
Some global_object;
thread_local Some thread_object;
struct A {
Some m_object;
void foo(Some& object) {
std::vector<std::reference_wrapper<Some>> objects;
objects.emplace_back(object);
objects.emplace_back(m_object);
objects.emplace_back(thread_object);
objects.emplace_back(global_object);
for (const auto& o : objects) {
// some process without copying
}
}
};
Тем самым мы можем обработать обработать кучу данных из разных источников без необходимости их копирования; накладные расходы будут только на внутряночку
std::reference_wrapper
(а это обычный указатель) и на сам std::vector
.И всё было бы хорошо, если бы оно было хорошо, но, к сожалению, оно не хорошо.
Видя, какое удобство и магию предоставляет этот
std::reference_wrapper
, люди забывают, что и обращаться с ним нужно так же, как с обычной ссылкой, под которую он мимикрирует.Вот буквально сегодня я увидел примерно вот такое:
struct Context {
std::optional<std::reference_wrapper<std::string>> m_id = std::nullopt;
}
Context createContext() {
Context ctx;
std::string guid = generateGUID();
ctx.m_id = guid;
return ctx;
}
И всё, пиздец котёнку. Успело попасть в релизную ветку, благо на тестировании стали ловить странные падения.
Как программист вообще мог такое написать и так облажаться? Очень просто: это было два программиста.
Первый - внедрил использование
std::optional<std::reference_wrapper<std::string>>
, второй не понял что такое этот ваш std::reference_wrapper
и поместил туда объект с меньшим временем жизни, чем контекст.