Как установить Геншин Импакт на телефон, который не поддерживает гугл, если пишет ошибку:
Кажется, тут есть: https://m.apkpure.com/ru/
Кстати, на Ответах@ нашлось (вчера один товарищ запостил).
Prizmo 67Ученик (218) 2 года назад
Я совру если скажу что ты мне помог
m p Мудрец (13413) Prizmo 67, Ну вообще ответов не много. Видимо тема вопроса не нашла отклика. Буду банален– посетите сайт 4pda.
У меня такая же проблема, скажи пожалуйста, как решить, если у тебя получилось
Ангелина ТюхтееваЗнаток (345) 2 года назад
оказалось, что телефон просто слабый для геншина. поэтому его не было в маркете, и скачивать с интернета не получалось.
Ангелина Горелова, а игра работает?
У меня HONOR 9s и для этого мобильного устроиства такая проблема не редкость.
И я нашёл способ который помог лично мне. Он довольно прост. Качаете установщик SAI. Затем качаете Gspace.
В Gspace вы клонируете SAI и устанавливаете apk файл.
Так как Gspace при проверке пакета выдаёт данные совершенно другой модели телефона и проблем с установкой не будет.
Матвей Константинов Ученик (104) 2 года назад
Не работает, тоже 9s. Но спасибо.
Самир Аввясов Ученик (101) Матвей Константинов , подскажи какие нибудь игры для хонора 9s, поиграть не во что.
виктория женоваЗнаток (301) 1 год назад
смогла запустить, но в игре черный экран и она вылетает
у меня тоже самое
Самир АввясовУченик (101) 1 год назад
Кто то смог запустить или нет?
Даже если ты скачаешь гугл то не как не поможет
у меня всё норм
Решение довольно просто. Из AppGallery нужно скачать не первую попавшуюся версию приложения, а немного другую. Найдя нужное приложение, не торопитесь нажать кнопку скачивания, а прокрутите в конец и обратите внимание на наличие версий. У меня, например, в случае с microsoft solitaire collection, по умолчанию скачивается версия с единичкой в конце имени файла. При установке выдается ошибка CPU_ABI. Я взял версию с ноликом и вуаля! Она работает на Huawei!
Android Studio 2.2.2 Ошибка «No CPU/ABI system image available for this target»
Создаю программу впервые. При помощи AVD manager хочу создать AVD но поле CPU/ABI остаётся пустым, не высвечивается кнопка ОК и пишет:
No CPU/ABI system image available for this target
Отслеживать
6,488 6 6 золотых знаков 24 24 серебряных знака 31 31 бронзовый знак
задан 19 ноя 2016 в 0:51
1 1 1 бронзовый знак
2 ответа 2
Сортировка: Сброс на вариант по умолчанию
Вам нужно скачать системный образ Android. Делается это, насколько я помню, в SDK Manager’e.
Отслеживать
ответ дан 19 ноя 2016 в 0:53
FullyRetarded FullyRetarded
121 1 1 серебряный знак 11 11 бронзовых знаков
если это комментарий, отправьте тревогу модераторам, чтобы перенесли ответ в комментарий. если это решение, то все хорошо(только лишний текст удалите).
19 ноя 2016 в 13:29
На мой взгляд, это вполне ответ. Что тут ещё можно добавить-то, скриншот кнопки «Download»?
19 ноя 2016 в 15:18
Впрочем, можно добавить пару слов про CPU/ABI system image, что это такое и почему нужно качать отдельно. И если нужно будет выбрать из нескольких — то как выбрать.
19 ноя 2016 в 15:18
Если речь о eclipse, то нужно зайти Window-> Android SDK manager и установить для нужних платформ «ARM EABI v7a System Image». Тут есть то, что Вам нужно https://stackoverflow.com/questions/13488419/unable-to-create-android-virtual-device.
Отслеживать
ответ дан 4 мая 2017 в 6:50
Уточните ваш вопрос — «для нужних платформ «ARM EABI v7a System Image»» — чем это поможет?
4 мая 2017 в 7:20
-
Важное на Мете
Похожие
Подписаться на ленту
Лента вопроса
Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.
Дизайн сайта / логотип © 2024 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2024.1.8.3130
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
Как установить несовместимые с Android-устройством приложения в обход ограничений Google Play
Порой случаются ситуации, когда мы заходим на Google Play, находим какое-либо приложение, пытаемся его скачать, а система выдает ответ – «Приложение не совместимо с Вашим устройством».
Такое может произойти по двум причинам:
1. Ваше устройство находится в том регионе, в котором запрещено использование этого приложения. Иногда сложно сказать по какой причине это происходит, но создатели софта ставят на его эксплуатацию региональные ограничения.
2. Вы используете несовместимую с приложением версию Android. К примеру, на Вашем гаджете версия 4.0, а необходима 5.0 или выше.
Но не расстраивайтесь, прочитав данную инструкцию, Вы узнаете, как обойти ограничение Google Play и установить приложения, которые без использования метода, описанного ниже, не установились бы.
Приложение ZenMate VPN Security & Privacy
В основе способа — использование простейшей программы ZenMate VPN Security & Privacy, предназначенной для обеспечения анонимности и безопасности интернет-серфигнга. Данное приложение дает возможность имитировать выход в сеть из США, Великобритании, Германии, Гонконга или Швейцарии с соответствующим изменением ip-адреса и отменой блокировки Google Play.
Порядок действий:
1. Скачиваете на смартфон или планшет бесплатную программу ZenMate по ссылке:
2. Производите установку и запуск программы.
3. Регистрируетесь — указываете любой e-mail и пароль (подтверждения или активации аккаунта с почты не требуется).

4. Указываете любую из предлагаемых локаций.

5. Подтверждаем полученный от запрос на подключение (нажать «ОК»).

6. Заходите в Google Play и спокойно скачиваете или обновляете все, что вам необходимо.
Загрузите .apk файл, используя специальные сайты
Еще более простым и, возможно, более надежным решением является использование веб-сайтов, которые анализируют содержимое Google Play позволяют загружать файлы с расширением .apk напрямую.


Вы просто должны будете скопировать адрес страницы с приложением в Google Play и скачать .apk файл на ваш смартфон или компьютер. Если Вы загрузили .apk файл на компьютер, просто переместите его в память Вашего устройства и, используя файловый менеджер, откройте и установите его.
Используйте другие магазины приложений
Если Вы столкнулись с тем, что не можете загрузить какое-либо приложение, используйте для его поиска и загрузки другие магазины, например Amazon App Store. Кроме магазина Amazon, в Интернете сети есть целый ряд сторонних магазинов приложений, таких как GetJar , SlideME, F-Droid, Mobogenie, Samsung Galaxy Apps store, и множество других, где могут содержаться приложения, которые Вы ищите. Помните правило – кто ищет, тот обязательно найдет!
Пользователь обнаружил, что приложения Google больше не удаётся вручную установить на смартфоны с SoC Kirin
Судя по всему, компания Google перешла к решительным действиям и перекрыла возможность установки фирменных приложений на устройства Huawei.

Huawei уже больше года вынуждена выпускать флагманы и более простые новые смартфоны без установленных приложений и сервисов Google из-за санкций со стороны США. Тем не менее, пользователи находили обходные пути и устанавливали приложения Google вручную. Теперь с установкой вручную появились сложности.
На проблему обратил внимание один из пользователей социального новостного ресурса Reddit. Он сообщил, что годами вручную загружал установочные файлы APK для Google Maps (Google Карты), а также других приложений, и вручную устанавливал их. Тем не менее, недавно этот трюк впервые потерпел неудачу.

При попытке установить свежую версию Google Maps из APK на смартфоне появилось сообщение об ошибке установки, а в качестве причины указывалось следующее: «Это приложение не совместимо с CPU вашего устройства», хотя прошлая версия этого же приложения на этом же смартфоне не имела такой проблемы.
Пользователь протестировал обновлённые APK свежих версий приложений Google на «гораздо более старом» смартфоне Samsung и установка прошла «идеально». Он также не поленился и попробовал установить эти же обновлённые приложения Google на другие устройства Huawei, включая Huawei P30, P20, P40, и так далее. И во всех случаях установка на смартфоны Huawei терпела крах из-за «несовместимого CPU».
Huawei и Google пока не давали официальных комментариев по этому поводу.
Дополнено: российский офис Huawei опровергает проблемы с установкой приложений Google на смартфоны с процессорами Kirin, уточняя, что может комментировать только ситуацию в России.
Android Studio 2.2.2 Ошибка «No CPU/ABI system image available for this target»
Создаю программу впервые. При помощи AVD manager хочу создать AVD но поле CPU/ABI остаётся пустым, не высвечивается кнопка ОК и пишет:
No CPU/ABI system image available for this target
Отслеживать
6,488 6 6 золотых знаков 24 24 серебряных знака 31 31 бронзовый знак
задан 19 ноя 2016 в 0:51
1 1 1 бронзовый знак
2 ответа 2
Сортировка: Сброс на вариант по умолчанию
Вам нужно скачать системный образ Android. Делается это, насколько я помню, в SDK Manager’e.
Отслеживать
ответ дан 19 ноя 2016 в 0:53
FullyRetarded FullyRetarded
121 1 1 серебряный знак 11 11 бронзовых знаков
если это комментарий, отправьте тревогу модераторам, чтобы перенесли ответ в комментарий. если это решение, то все хорошо(только лишний текст удалите).
19 ноя 2016 в 13:29
На мой взгляд, это вполне ответ. Что тут ещё можно добавить-то, скриншот кнопки «Download»?
19 ноя 2016 в 15:18
Впрочем, можно добавить пару слов про CPU/ABI system image, что это такое и почему нужно качать отдельно. И если нужно будет выбрать из нескольких — то как выбрать.
19 ноя 2016 в 15:18
Если речь о eclipse, то нужно зайти Window-> Android SDK manager и установить для нужних платформ «ARM EABI v7a System Image». Тут есть то, что Вам нужно https://stackoverflow.com/questions/13488419/unable-to-create-android-virtual-device.
Отслеживать
ответ дан 4 мая 2017 в 6:50
Уточните ваш вопрос — «для нужних платформ «ARM EABI v7a System Image»» — чем это поможет?
4 мая 2017 в 7:20
-
Важное на Мете
Похожие
Подписаться на ленту
Лента вопроса
Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.
Дизайн сайта / логотип © 2024 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2024.1.8.3130
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
Отключение фикса Meltdown и Spectre в Windows
На сайте майкрософт размещена информация о том, как можно проверить подвержена ли ОС атакам meltdown. Там же имеется информация, как можно отключить последнее исправление.

Учитывая, что в интернете не утихают слухи о катастрофическом падении производительности и даже появляются сравнительные тесты «до» и «после» информация по отключению данной заплатки может оказаться полезной.
Сразу к делу: отключить можно внесением или корректировкой двух параметров в реестре.
С сайта майкрософт:
Включение или отключение фикса отдельно для CVE-2017-5715 и CVE-2017-5754 (Spectre и Meltdown)
Как включить фикс CVE-2017-5715 и CVE-2017-5754
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management" /v FeatureSettingsOverride /t REG_DWORD /d 0 /f reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management" /v FeatureSettingsOverrideMask /t REG_DWORD /d 3 /f
Как отключить фикс CVE-2017-5715 и CVE-2017-5754
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management" /v FeatureSettingsOverride /t REG_DWORD /d 3 /f reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management" /v FeatureSettingsOverrideMask /t REG_DWORD /d 3 /f
Включение или отключение фикса отдельно для CVE 2017-5715 (Spectre)
Как включить фикс CVE-2017-5715
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management" /v FeatureSettingsOverride /t REG_DWORD /d 0 /f reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management" /v FeatureSettingsOverrideMask /t REG_DWORD /d 1 /f
Как отключить фикс CVE-2017-5715
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management" /v FeatureSettingsOverride /t REG_DWORD /d 1 /f reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management" /v FeatureSettingsOverrideMask /t REG_DWORD /d 1 /f
Примечание * Установка значения 3 для FeatureSettingsOverrideMask является одинаковым для обоих случаев.
Примечание.* Отключение и включение посредством изменения параметров реестра потребует перезагрузки компьютера и права администратора.
Примечание.* Изменять MinVmVersionForCpuBasedMitigations нет необходимости.
Проверка наличия уязвимости в системе при помощи powershell модуля SpeculationControl
Предполагается, что ExecutionPolicy в powershell настроена на нужный уровень (Bypass или Unrestricted).
Установка модуля PowerShell:
Install-Module SpeculationControl
На оба вопроса отвечаем «Y».
Import-Module SpeculationControl
Get-SpeculationControlSettings
Результат в случае полной «защищенности» ПК:
BTIHardwarePresent : True BTIWindowsSupportPresent : True BTIWindowsSupportEnabled : True BTIDisabledBySystemPolicy : True BTIDisabledByNoHardwareSupport : True KVAShadowRequired : True KVAShadowWindowsSupportPresent : True KVAShadowWindowsSupportEnabled : True KVAShadowPcidEnabled : True
После применения изменения настроек и перезагрузки:
BTIHardwarePresent : False BTIWindowsSupportPresent : False BTIWindowsSupportEnabled : False BTIDisabledBySystemPolicy : False BTIDisabledByNoHardwareSupport : False KVAShadowRequired : False KVAShadowWindowsSupportPresent : False KVAShadowWindowsSupportEnabled : False KVAShadowPcidEnabled : False
А вот вопросы нужно это делать или нет, есть ли смысл или нет и остаются открытыми.
Официальное обновление отключающее патч CVE 2017-5715 для всех поддерживаемых windows
www.catalog.update.microsoft.com/Search.aspx?q=KB4078130
P.P.S.: Если у кого-нибудь есть возможность протестировать есть ли вообще изменения в плане производительности, то было бы очень замечательно.
Пользователь обнаружил, что приложения Google больше не удаётся вручную установить на смартфоны с SoC Kirin
Судя по всему, компания Google перешла к решительным действиям и перекрыла возможность установки фирменных приложений на устройства Huawei.

Huawei уже больше года вынуждена выпускать флагманы и более простые новые смартфоны без установленных приложений и сервисов Google из-за санкций со стороны США. Тем не менее, пользователи находили обходные пути и устанавливали приложения Google вручную. Теперь с установкой вручную появились сложности.
На проблему обратил внимание один из пользователей социального новостного ресурса Reddit. Он сообщил, что годами вручную загружал установочные файлы APK для Google Maps (Google Карты), а также других приложений, и вручную устанавливал их. Тем не менее, недавно этот трюк впервые потерпел неудачу.

При попытке установить свежую версию Google Maps из APK на смартфоне появилось сообщение об ошибке установки, а в качестве причины указывалось следующее: «Это приложение не совместимо с CPU вашего устройства», хотя прошлая версия этого же приложения на этом же смартфоне не имела такой проблемы.
Пользователь протестировал обновлённые APK свежих версий приложений Google на «гораздо более старом» смартфоне Samsung и установка прошла «идеально». Он также не поленился и попробовал установить эти же обновлённые приложения Google на другие устройства Huawei, включая Huawei P30, P20, P40, и так далее. И во всех случаях установка на смартфоны Huawei терпела крах из-за «несовместимого CPU».
Huawei и Google пока не давали официальных комментариев по этому поводу.
Дополнено: российский офис Huawei опровергает проблемы с установкой приложений Google на смартфоны с процессорами Kirin, уточняя, что может комментировать только ситуацию в России.
Детерминированные исключения и обработка ошибок в «C++ будущего»
Странно, что на Хабре до сих пор не было упомянуто о наделавшем шуму предложении к стандарту C++ под названием «Zero-overhead deterministic exceptions». Исправляю это досадное упущение.
Если вас беспокоит оверхед исключений, или вам приходилось компилировать код без поддержки исключений, или просто интересно, что будет с обработкой ошибок в C++2b (отсылка к недавнему посту), прошу под кат. Вас ждёт выжимка из всего, что сейчас можно найти по теме, и пара опросов.
Разговор далее будет вестись не только про статические исключения, но и про связанные предложения к стандарту, и про всякие другие способы обработки ошибок. Если вы зашли сюда поглядеть на синтаксис, то вот он:
double safe_divide(int x, int y) throws(arithmetic_error) < if (y == 0) < throw arithmetic_error::divide_by_zero; >else < return as_double(x) / y; >> void caller() noexcept < try < cout catch (arithmetic_error e) < cout >
Если конкретный тип ошибки неважен/неизвестен, то можно использовать просто throws и catch (std::error e) .
Полезно знать
std::optional и std::expected
Пусть мы решили, что ошибка, которая потенциально может возникнуть в функции, недостаточно «фатальная», чтобы бросать из неё исключение. Традиционно информацию об ошибке возвращают с помощью выходного параметра (out parameter). Например, Filesystem TS предлагает ряд подобных функций:
uintmax_t file_size(const path& p, error_code& ec);
(Не бросать же исключение из-за того, что файл не найден?) Тем не менее, обработка кодов ошибок громоздкая и подвержена багам. Код ошибки легко забыть проверить. Современные стили кода запрещают использование выходных параметров, вместо них рекомендуется возвращать структуру, содержащую весь результат.
Boost вот уже некоторое время предлагает изящное решение для обработки таких «не-фатальных» ошибок, которые в определённых сценариях могут происходить сотнями в корректной программе:
expected file_size(const path& p);
Тип expected похож на variant , но предоставляет удобный интерфейс для работы с «результатом» и «ошибкой». По умолчанию, в expected хранится «результат». Реализация file_size может выглядеть как-то так:
file_info* info = read_file_info(p); if (info != null) < uintmax_t size = info->size; return size; // else < error_code error = get_error(); return std::unexpected(error); //
Если причина ошибки нам неинтересна, или ошибка может заключаться только в «отсутствии» результата, то можно использовать optional :
optional parse_int(const std::string& s); optional get_or_null(map m, const T& key);
В C++17 из Boost в std попал optional (без поддержки optional ); в C++20, возможно, добавят expected (это только Proposal, спасибо RamzesXI за поправку).
Contracts
Контракты (не путать с концептами) — новый способ наложить ограничения на параметры функции, добавленный в C++20. Добавлены 3 аннотации:
- expects проверяет параметры функции
- ensures проверяет возвращаемое значение функции (принимает его в качестве аргумента)
- assert — цивилизованная замена макросу assert
double unsafe_at(vector v, size_t i) [[expects: i < v.size()]]; double sqrt(double x) [[expects: x >= 0]] [[ensures ret: ret >= 0]]; value fetch_single(key e) < vectorresult = fetch(vector); [[assert result.size() == 1]]; return v[0]; >
Можно настроить, чтобы нарушение контрактов:
- Вызывало Undefined Behaviour, или
- Проверялось и вызывало пользовательский обработчик, после чего std::terminate
Продолжать работу программы после нарушения контракта никак нельзя, потому что компиляторы используют гарантии из контрактов для оптимизации кода функции. Если есть малейшее сомнение в том, что контракт выполнится, стоит добавить дополнительную проверку.
std::error_code
Библиотека , добавленная в C++11, позволяет унифицировать обработку кодов ошибок в вашей программе. std::error_code состоит из кода ошибки типа int и указателя на объект какого-нибудь класса-наследника std::error_category. Этот объект, по сути, играет роль таблицы виртуальных функций и определяет поведение данного std::error_code .
Чтобы создавать свои std::error_code , вы должны определить свой класс-наследник std::error_category и реализовать виртуальные методы, самым важным из которых является:
virtual std::string message(int c) const = 0;
Нужно также создать глобальную переменную вашего std::error_category . Обработка ошибок при помощи error_code + expected выглядит как-то так:
template using result = expected; my::file_handle open_internal(const std::string& name, int& error); auto open_file(const std::string& name) -> result < int raw_error = 0; my::file_handle maybe_result = open_internal(name, &raw_error); std::error_code error; if (error) < return unexpected; > else < return my::file; > >
Важно, что в std::error_code значение 0 означает отсутствие ошибки. Если для ваших кодов ошибок это не так, то перед тем, как конвертировать системный код ошибки в std::error_code , надо заменить код 0 на код SUCCESS, и наоборот.
Все системные коды ошибок описаны в errc и system_category. Если на определённом этапе ручной проброс кодов ошибки становится слишком муторным, то всегда можно завернуть код ошибки в исключение std::system_error и выбросить.
Destructive move / Trivially relocatable
Пусть вам нужно создать очередной класс объектов, владеющих какими-нибудь ресурсами. Скорее всего, вы захотите сделать его некопируемым, но перемещаемым (moveable), потому что с unmoveable объектами неудобно работать (до C++17 их нельзя было вернуть из функции).
Но вот беда: перемещённый объект в любом случае нужно удалить. Поэтому необходимо особое состояние "moved-from", то есть "пустого" объекта, который ничего не удаляет. Получается, каждый класс C++ обязан иметь пустое состояние, то есть невозможно создать класс с инвариантом (гарантией) корректности, от конструктора до деструктора. Например, невозможно создать корректный класс open_file файла, который открыт на всём протяжении времени жизни. Странно наблюдать это в одном из немногих языков, активно использующих RAII.
Другая проблема — зануление старых объектов при перемещении добавляет оверхед: заполнение std::vector> может быть до 2 раз медленнее, чем std::vector из-за кучи занулений старых указателей при перемещении, с последующим удалением пустышек.
Разработчики C++ давно облизываются на Rust, где у перемещённых объектов не вызываются деструкторы. Эта фича называется Destructive move. К сожалению, Proposal Trivially relocatable не предлагает добавить её в C++. Но проблему оверхеда решит.
Класс считается Trivially relocatable, если две операции: перемещения и удаления старого объекта — эквивалентны memcpy из старого объекта в новый. Старый объект при этом не удаляется, авторы называют это "drop it on the floor".
Тип является Trivially relocatable с точки зрения компилятора, если выполняется одно из следующих (рекурсивных) условий:
- Он trivially moveable + trivially destructible (например, int или POD структура)
- Это класс, помеченный атрибутом [[trivially_relocatable]]
- Это класс, все члены которого являются Trivially relocatable
Использовать эту информацию можно с помощью std::uninitialized_relocate , которая исполняет move init + delete обычным способом, или ускоренным, если это возможно. Предлагается пометить как [[trivially_relocatable]] большинство типов стандартной библиотеки, включая std::string , std::vector , std::unique_ptr . Оверхед std::vector> с учётом этого Proposal исчезнет.
Что не так с исключениями сейчас?
Механизм исключений C++ разрабатывался в 1992 году. Были предложены различные варианты реализации. Из них в итоге был выбран механизм таблиц исключений, которые гарантируют отсутствие оверхеда для основного пути выполнения программы. Потому что с самого момента их создания создания предполагалось, что исключения должны выбрасываться очень редко.
Недостатки динамических (то есть обычных) исключений:
- В случае выброшенного исключения оверхед составляет в среднем порядка 10000-100000 циклов CPU, а в худшем случае может достигать порядка миллисекунд
- Увеличение размера бинарного файла на 15-38%
- Несовместимость с программным интерфейсом С
- Неявная поддержка проброса исключений во всех функциях, кроме noexcept . Исключение может быть выброшено практически в любом месте программы, даже там, где автор функции его не ожидает
Из-за этих недостатков существенно ограничивается область применения исключений. Когда исключения не могут применяться:
- Там, где важен детерминизм, то есть там, где недопустимо, чтобы код "иногда" работал в 10, 100, 1000 раз медленнее, чем обычно
- Когда они не поддерживаются в ABI, например, в микроконтроллерах
- Когда значительная часть кода написана на С
- В компаниях с большим грузом легаси-кода (Google Style Guide, Qt). Если в коде есть хоть одна не exception-safe функция, то по закону подлости через неё рано или поздно прокинут исключение и создадут баг
- В компаниях, набирающих программистов, которые понятия не имеют об exception safety
По опросам, на местах работы 52% (!) разработчиков исключения запрещены корпоративными правилами.
Но исключения — неотъемлемая часть C++! Включая флаг -fno-exceptions , разработчики теряют возможность использовать значительную часть стандартной библиотеки. Это дополнительно подстрекает компании насаждать собственные "стандартные библиотеки" и да, изобретать свой класс строки.
Но и это ещё не конец. Исключения — единственный стандартный способ отменить создание объекта в конструкторе и выдать ошибку. Когда они отключены, появляется такая мерзость, как двухфазная инициализация. Операторы тоже не могут использовать коды ошибок, поэтому они заменяются функциями вроде assign .
Proposal: исключения будущего
Новый механизм передачи исключений
Герб Саттер (Herb Sutter) в P709 описал новый механизм передачи исключений. Идейно, функция возвращает std::expected , однако вместо отдельного дискриминатора типа bool , который вместе с выравниванием будет занимать до 8 байт на стеке, этот бит информации передаётся каким-то более быстрым способом, например, в Carry Flag.
Функции, которые не трогают CF (таких большинство), получат возможность использовать статические исключения бесплатно — и в случае обычного возврата, и в случае проброса исключения! Функции, которые вынуждены будут его сохранять и восстанавливать, получат минимальный оверхед, и это всё равно будет быстрее, чем std::expected и любые обычные коды ошибок.
Выглядят статические исключения следующим образом:
int safe_divide(int i, int j) throws(arithmetic_errc) < if (j == 0) throw arithmetic_errc::divide_by_zero; if (i == INT_MIN && j == -1) throw arithmetic_errc::integer_divide_overflows; return i / j; >double foo(double i, double j, double k) throws(arithmetic_errc) < return i + safe_divide(j, k); >double bar(int i, double j, double k) < try < cout catch (erithmetic_errc e) < cout >
В альтернативной версии предлагается обязать ставить ключевое слово try в том же выражении, что вызов throws функции: try i + safe_divide(j, k) . Это сведёт число случаев использования throws функций в коде, не безопасном для исключений, практически к нулю. В любом случае, в отличие от динамических исключений, у IDE будет возможность как-то выделять выражения, бросающие исключения.
То, что выброшенное исключение не сохраняется отдельно, а кладётся прямо на место возвращаемого значения, накладывает ограничения на тип исключения. Во-первых, он должен быть Trivially relocatable. Во-вторых, его размер должен быть не очень большим (но это может быть что-то вроде std::unique_ptr ), иначе все функции будут резервировать больше места на стеке.
status_code
Библиотека , разработанная Найл Дуглас (Niall Douglas), будет содержать status_code — «новый, лучший» error_code . Основные отличия от error_code :
- status_code — шаблонный тип, который можно использовать для хранения практически любых мыслимых кодов ошибок (вместе с указателем на status_code_category ), без использования статических исключений
- T должен быть Trivially relocatable и копируемым (последнее, ИМХО, не должно быть обязательным). При копировании и удалении вызываются виртуальные функции из status_code_category
- status_code может хранить не только данные об ошибке, но и дополнительные сведения об успешно завершённой операции
- «Виртуальная» функция code.message() возвращает не std::string , а string_ref — довольно тяжёлый тип строки, представляющий собой виртуальный «возможно владеющий» std::string_view . Туда можно запихнуть string_view или string , или std::shared_ptr , или ещё какой-нибудь сумасшедший способ владения строкой. Найл утверждает, что #include сделало бы заголовок непозволительно «тяжёлым»
Далее, вводится errored_status_code — обёртка над status_code со следующим конструктором:
errored_status_code(status_code&& code) [[expects: code.failure() == true]] : code_(std::move(code)) <>
error
Тип исключения по умолчанию ( throws без типа), а также базовый тип исключений, к которому приводятся все остальные (вроде std::exception ) — это error . Он определён примерно так:
using error = errored_status_code;
То есть error — это такой «ошибочный» status_code , у которого значение ( value ) помещается в 1 указатель. Так как механизм status_code_category обеспечивает корректное удаление, перемещение и копирование, то теоретически в error можно сохранить любую структуру данных. На практике это будет один из следующих вариантов:
- Целые числа (int)
- std::exception_handle , то есть указатель на выброшенное динамическое исключение
- status_code_ptr , то есть unique_ptr на произвольный status_code .
Проблема в том, что случае 3 не планируется дать возможность привести error обратно к status_code . Единственное, что можно сделать — получить message() упакованного status_code . Чтобы иметь возможность достать обратно завёрнутое в error значение, надо выбросить его как динамическое исключение (!), потом поймать и завернуть в error . А вообще, Найл считает, что в error должны храниться только коды ошибок и строковые сообщения, чего достаточно для любой программы.
Чтобы различать разные виды ошибок, предлагается использовать «виртуальный» оператор сравнения:
try < open_file(name); >catch (std::error e) < if (e == filesystem_error::already_exists) < return; >else < throw my_exception("Unknown filesystem error, unable to continue"); >>
Использовать несколько catch-блоков или dynamic_cast для выбора типа исключения не получится!
Взаимодействие с динамическими исключениями
Функция может иметь одну из следующих спецификаций:
- noexcept : не бросает никаких исключений
- throws(E) : бросает только статические исключения
- (ничего): бросает только динамические исключения
throws подразумевает noexcept . Если динамическое исключение выбрасывается из «статической» функции, то оно заворачивается в error . Если статическое исключение выбрасывается из «динамической» функции, то оно заворачивается в исключение status_error . Пример:
void foo() throws(arithmetic_errc) < throw erithmetic_errc::divide_by_zero; >void bar() throws < // Код arithmetic_errc помещается в intptr_t // Допустимо неявное приведение к error foo(); >void baz() < // error заворачивается в исключение status_error bar(); >void qux() throws < // error достаётся из исключения status_error baz(); >
Исключения в C?!
Предложение предусматривает добавление исключений в один из будущих стандартов C, причём эти исключения будут ABI-совместимы со статическими исключениями C++. Структуру, аналогичную std::expected , пользователь должен будет объявлять самостоятельно, хотя избыточность можно убрать с помощью макросов. Синтаксис состоит из (для простоты будем так считать) ключевых слов fails, failure, catch.
int invert(int x) fails(float) < if (x != 0) return 1 / x; else return failure(2.0f); >struct expected_int_float < union < int value; float error; >; _Bool failed; >; void caller() < expected_int_float result = catch(invert(5)); if (result.failed) < print_error(result.error); return; >print_success(result.value); >
При этом в C++ тоже можно будет вызывать fails функции из C, объявляя их в блоках extern C . Таким образом, в C++ будет целая плеяда ключевых слов по работе с исключениями:
- throw() — удалено в C++20
- noexcept — спецификатор функции, функция не бросает динамические исключения
- noexcept(expression) — спецификатор функции, функция не бросает динамические исключения при условии
- noexcept(expression) — бросает ли выражение динамические исключения?
- throws(E) — спецификатор функции, функция бросает статические исключения
- throws = throws(std::error)
- fails(E) — функция, импортированная из C, бросает статические исключения
Итак, в C++ завезли (точнее, завезут) тележку новых инструментов для обработки ошибок. Далее возникает логичный вопрос:
Когда что использовать?
Направление в целом
Ошибки разделяются на несколько уровней:
- Ошибки программиста. Обрабатываются с помощью контрактов. Приводят к сбору логов и завершению работы программы в соответствие с концепцией fail-fast. Примеры: нулевой указатель (когда это недопустимо); деление на ноль; ошибки выделения памяти, не предусмотренные программистом.
- Непоправимые ошибки, предусмотренные программистом. Выбрасываются в миллион раз реже, чем обычный возврат из функции, что делает использование для них динамических исключений оправданным. Обычно в таких случаях требуется перезапустить целую подсистему программы или выдать ошибку при выполнении операции. Примеры: внезапно потеряна связь с базой данных; ошибки выделения памяти, предусмотренные программистом.
- Поправимые (recoverable) ошибки, когда что-то помешало функции выполнить свою задачу, но вызывающая функция, возможно, знает, что с этим делать. Обрабатываются с помощью статических исключений. Примеры: работа с файловой системой; другие ошибки ввода-вывода (IO); некорректные пользовательские данные; vector::at() .
- Функция успешно завершила свою задачу, пусть и с неожиданным результатом. Возвращаются std::optional , std::expected , std::variant . Примеры: stoi() ; vector::find() ; map::insert .
В стандартной библиотеке надёжнее всего будет полностью отказаться от использования динамических исключений, чтобы сделать компиляцию «без исключений» легальной.
errno
Функции, использующие errno для быстрой и минималистичной работы с кодами ошибок C и C++, должны быть заменены на fails(int) и throws(std::errc) , соответственно. Некоторое время старый и новый варианты функций стандартной библиотеки будут сосуществовать, потом старые объявят устаревшими.
Out of memory
Ошибки выделения памяти обрабатывает глобальный хук new_handler , который может:
- Устранить нехватку памяти и продолжить выполнение
- Выбросить исключение
- Аварийно завершить программу
Сейчас по умолчанию выбрасывается std::bad_alloc . Предлагается же по умолчанию вызывать std::terminate() . Если вам нужно старое поведение, замените обработчик на тот, который вам нужен, в начале main() .
Все существующие функции стандартной библиотеки станут noexcept и будут крашить программу при std::bad_alloc . В то же время, будут добавлены новые API вроде vector::try_push_back , которые допускают ошибки выделения памяти.
logic_error
Исключения std::logic_error , std::domain_error , std::invalid_argument , std::length_error , std::out_of_range , std::future_error сообщают о нарушении предусловия функции. В новой модели ошибок вместо них должны использоваться контракты. Перечисленные типы исключений не будут объявлены устаревшими, но почти все случаи их использования в стандартной библиотеке будут заменены на [[expects: …]] .
Текущее состояние Proposal
Proposal сейчас находится в состоянии черновика. Он уже довольно сильно поменялся, и ещё может сильно измениться. Некоторые наработки не успели опубликовать, так что предлагаемый API не совсем актуален.
Предложение описывается в 3 документах:
- P709 — первоначальный документ от Герба Саттера
- P1095 — детерминированные исключения в видении Найла Дугласа, некоторые моменты изменены, добавлена совместимость с языком C
- P1028 — API из тестовой реализации std::error
На настоящий момент не существует компилятора, который поддерживает статические исключения. Соответственно, сделать их бенчмарки пока невозможно.
При наилучшем раскладе детерминированные исключения будут готовы и попадут в C++23. Если не успеют, то, вероятно, попадут в C++26, так как комитет стандартизации, в целом, заинтересован темой.
Заключение
Многие детали предлагаемого подхода к обработке исключений я опустил или умышленно упростил, зато прошёлся по большинству тем, требующихся для понимания статических исключений. Если возникли дополнительные вопросы, то задайте их в комментариях или обратитесь к документам по ссылкам выше. Любые поправки приветствуются.
И конечно, обещанные опросы ^^