Telegram Group & Telegram Channel
#creepy

Heterogeneous Lookup

Что будет, если попытаться вызвать .find()/.contains()/etc. у ассоциативных контейнеров (std::set/std::map/unordered-версии) с ключом, который не совпадает по типу? 🤔

std::map<std::string, int> m;
// ...
if (m.contains("foobar")) { ... }

У std::map есть дефолтный компаратор третьим аргументом в шаблоне - std::less<Key>. Компаратор нужен для поиска в контейнере.

Компаратор это структура, у которой должен быть определен bool operator(); выглядит оно примерно так:
constexpr bool operator()(const Key &lhs, const Key &rhs) const {
return lhs < rhs;
}

То есть тип аргумента должен совпадать с типом ключа. Возвращаясь к примеру в начале: "foobar" имеет тип const char[7]. Он может "разложиться" в тип const char*, быть преобразован в тип std::string_view или std::string. Поэтому, к сожалению, по overload resolution создается временной объект std::string. 💩

Проверить, что это именно так, можно через строку с кастомным аллокатором (см. определение std::string), который логирует запрос на аллокации.
using traceable_string = std::basic_string<char, std::char_traits<char>, trace_allocator<char>>;
Проверяемые строки должны быть достаточно длинными, чтобы обойти Small String Optimization и вызвать аллокацию, в моем окружении это от 16 символов - код на godbolt.

Но зачем создавать std::string, если разные строковые типы сравниваемы между собой? В C++14 проблему решили лютым костылем 🩼: сделали std::less<> = std::less<void> и переопределили std::less<void> кастомно так:
template <class Key1, class Key2>
constexpr auto operator()(Key1&& lhs, Key2&& rhs) const
return static_cast<Key1&&>(lhs) < static_cast<Key2&&>(rhs);
}

Теперь для перфоманса нужно помнить этот хак и делать
std::map<std::string, int, std::less<>> m;
тогда лишних аллокаций не будет - код на godbolt. Это называется громким словом heterogeneous lookup.

Я не смог найти причину, почему это не сделали поведением по умолчанию. Я порылся в библиотеках с кастомными контейнерами и вижу два подхода к вопросу:
(1) homogenous lookup по умолчанию (как в STL) - пример boost::container::map
(2) heterogeneous lookup по умолчанию - пример хэш таблицы в Abseil (от Google), аналог std::unordered_map/set

Перф неплохо улучшается, пример расследования для unordered контейнеров - там цифры от 20% до 35%.



group-telegram.com/cxx95/25
Create:
Last Update:

#creepy

Heterogeneous Lookup

Что будет, если попытаться вызвать .find()/.contains()/etc. у ассоциативных контейнеров (std::set/std::map/unordered-версии) с ключом, который не совпадает по типу? 🤔

std::map<std::string, int> m;
// ...
if (m.contains("foobar")) { ... }

У std::map есть дефолтный компаратор третьим аргументом в шаблоне - std::less<Key>. Компаратор нужен для поиска в контейнере.

Компаратор это структура, у которой должен быть определен bool operator(); выглядит оно примерно так:
constexpr bool operator()(const Key &lhs, const Key &rhs) const {
return lhs < rhs;
}

То есть тип аргумента должен совпадать с типом ключа. Возвращаясь к примеру в начале: "foobar" имеет тип const char[7]. Он может "разложиться" в тип const char*, быть преобразован в тип std::string_view или std::string. Поэтому, к сожалению, по overload resolution создается временной объект std::string. 💩

Проверить, что это именно так, можно через строку с кастомным аллокатором (см. определение std::string), который логирует запрос на аллокации.
using traceable_string = std::basic_string<char, std::char_traits<char>, trace_allocator<char>>;
Проверяемые строки должны быть достаточно длинными, чтобы обойти Small String Optimization и вызвать аллокацию, в моем окружении это от 16 символов - код на godbolt.

Но зачем создавать std::string, если разные строковые типы сравниваемы между собой? В C++14 проблему решили лютым костылем 🩼: сделали std::less<> = std::less<void> и переопределили std::less<void> кастомно так:
template <class Key1, class Key2>
constexpr auto operator()(Key1&& lhs, Key2&& rhs) const
return static_cast<Key1&&>(lhs) < static_cast<Key2&&>(rhs);
}

Теперь для перфоманса нужно помнить этот хак и делать
std::map<std::string, int, std::less<>> m;
тогда лишних аллокаций не будет - код на godbolt. Это называется громким словом heterogeneous lookup.

Я не смог найти причину, почему это не сделали поведением по умолчанию. Я порылся в библиотеках с кастомными контейнерами и вижу два подхода к вопросу:
(1) homogenous lookup по умолчанию (как в STL) - пример boost::container::map
(2) heterogeneous lookup по умолчанию - пример хэш таблицы в Abseil (от Google), аналог std::unordered_map/set

Перф неплохо улучшается, пример расследования для unordered контейнеров - там цифры от 20% до 35%.

BY C++95


Warning: Undefined variable $i in /var/www/group-telegram/post.php on line 260

Share with your friend now:
group-telegram.com/cxx95/25

View MORE
Open in Telegram


Telegram | DID YOU KNOW?

Date: |

Telegram has become more interventionist over time, and has steadily increased its efforts to shut down these accounts. But this has also meant that the company has also engaged with lawmakers more generally, although it maintains that it doesn’t do so willingly. For instance, in September 2021, Telegram reportedly blocked a chat bot in support of (Putin critic) Alexei Navalny during Russia’s most recent parliamentary elections. Pavel Durov was quoted at the time saying that the company was obliged to follow a “legitimate” law of the land. He added that as Apple and Google both follow the law, to violate it would give both platforms a reason to boot the messenger from its stores. The regulator took order for the search and seizure operation from Judge Purushottam B Jadhav, Sebi Special Judge / Additional Sessions Judge. Since January 2022, the SC has received a total of 47 complaints and enquiries on illegal investment schemes promoted through Telegram. These fraudulent schemes offer non-existent investment opportunities, promising very attractive and risk-free returns within a short span of time. They commonly offer unrealistic returns of as high as 1,000% within 24 hours or even within a few hours. And while money initially moved into stocks in the morning, capital moved out of safe-haven assets. The price of the 10-year Treasury note fell Friday, sending its yield up to 2% from a March closing low of 1.73%. The next bit isn’t clear, but Durov reportedly claimed that his resignation, dated March 21st, was an April Fools’ prank. TechCrunch implies that it was a matter of principle, but it’s hard to be clear on the wheres, whos and whys. Similarly, on April 17th, the Moscow Times quoted Durov as saying that he quit the company after being pressured to reveal account details about Ukrainians protesting the then-president Viktor Yanukovych.
from us


Telegram C++95
FROM American