Здесь лишь часть.
1. Декомпозиция при объявлении (англ. structural bindings)
int main()
{
std::map<std::string, std::string> map;
auto [iterator1, succeed1] = map.try_emplace("key", "abc");
// Вы можете раскладывать key и value прямо в range-based for
for (auto&& [key, value] : map)
{
std::cout << key << ": " << value << "\n";
}
}
2. Атрибуты nodiscard, fallthrough, maybe_unused
Завершайте все блоки case, кроме последнего, либо атрибутом [[fallthrough]], либо инструкцией break;
Используйте [[nodiscard]] для функций, возвращающих код ошибки или владеющий указатель (неважно, умный или нет).
Используйте [[maybe_unused]] для переменных, которые нужны только для проверки в assert.
3. Классы optional и variant
Предпочитайте optional<T> вместо unique_ptr<T> для композиции объекта T, время жизни которого короче времени жизни владельца.
для PIMPL используйте unique_ptr<Impl>, потому что определение Impl скрыто в файле реализации класса.
Используйте тип variant вместо any везде, где это возможно. И вместо enum (но не всегда).
4. Используйте функции std::size, std::data, std::begin, std::end
Используйте std::size для измерения длины C-style массива.
Используйте std::data для получения изменяемого указателя начало строки, массива или std::vector<>.
5. Используйте std::filesystem
Передавайте std::filesystem::path вместо строк во всех параметрах, в которых подразумевается путь.
6. Прекратите переизобретать clamp, int_to_string и string_to_int