На мой рабоче-крестьянский взгляд exception safety означает не отсутствие исключений, а отсутствие проблем при возникновении исключений. В данной статье показан конструктор копирования DynamicArray, который не обеспечивает никаких гарантий exception safety:
DynamicArray(const DynamicArray& other)
: data_(new T[other.capacity_]),
size_(other.size_),
capacity_(other.capacity_) {
// Кто будет освобождать память по указателю data_ если в одной
// из строчек ниже возникнет исключение?
std::cout << "Copy constructor (copying " << size_ << " elements)\n";
std::copy(other.data_, other.data_ + size_, data_);
}
Где это может пригодиться на практике лучше не спрашивать :) Но с точки зрения возможности получить const && у std::move для константного объекта есть своя логика.
Да уж... Столько хорошей информации и правильных слов в самой статье, а потом хоба! И реализация DynamicArray в которой конструктор копирования не exception safe :(((
PS. Поскольку DynamicArray -- это всего лишь демонстрация, то придираться к тому, что он поддерживает только те T, которые являются DefaultConstructible, нет смысла.
Начиная с++11 шаблоны стали лечить, чтобы они были полезным инструментом
Пытаюсь оглянуться назад в 1995-й год, когда шаблоны начали появляться в доступных мне компиляторах... Да ведь они и тогда выглядели ну прям киллер-фичей, которой больше нигде не было. Из более-менее близкого к тогдашнему мейнстриму вспоминается разве что Ada со своим обобщенным программированием, но в Ada тогда еще не было ООП. А в C++ шаблоны были и для функций, и для классов, и даже для отдельных методов класса.
А уж сколько кода на шаблонах было написано до принятия С++11... Как-то сложно представить себе что все это было сделано на "неполезном" инструменте.
Да, когда исключения бросаются, то они могут дать просадку производительности на порядок, а то и на два. Кроме того, заранее неизвестно, сколько именно займет обработка исключения. Поэтому исключения под запретом в real-time. А это ведет к сегментированию в C++ (т.е. есть ниши где исключения под запретом, а есть где нет, и эти ниши сложно пересечь).
Я к тому, что если бы исключения были бы сделаны иначе (например, как в Eiffel) и были бы более дешевыми при использовании, такой проблемы с сегментированием в C++, возможно, не было бы.
Саттер несколько лет назад пытался продвинуть новый механизм для исключений. Но не взлетело до сих пор.
И часто она вам нужна, для не арифметических типов (или обертами над ними)?
Бывает. Но тут можно и другую аналогию привести: так ли часто парашютистам нужен запасной парашют? И если он нужен не часто, то есть ли смысл от него отказаться совсем.
Ну сделайте MyType::ToString и живите щастливо.
lavrov.jpg
При чем здесь MyType::ToString? Каким боком этот ваш "совет" поможет в DSL-естроении (например, вот таком)?
Оч странный у вас контраргумент. Да, в каких-то местах оно работает, в каких-то нет.
Т.е. вы пишите библиотеки, которые в каких-то местах работают, а в каких-то нет?
Контраргумент, которого вы, вероятно, не поняли, состоял в том, что если ваш код (например, ваша библиотека) использует чужой код, в котором исключения возможны (например, виде std::bad_alloc который может вылететь из push_back), то рассуждения о том, чтобы библиотека сама не бросала исключений становятся, скорее, росказнями, чем рассуждениями.
если ваш код не бросает исключений, то как бы...
Мой код, как правило, базируется на куче чужого кода.
Chromium собирается без поддержки исключений
Почему Google не использует у себя исключений уже многократно обсуждалось. А тем, кто не в курсе, можно попробовать прочитать соответствующий раздел из Google Code Style. С признанием того, что у исключений таки больше преимуществ. Только вот Google теперь дешевле продолжать писать без них.
Кроме того, далеко не у всех есть бюджеты Google. Если вы можете себе позволить писать больше менее надежного кода -- OK, можете извращаться как хотите, ваше право тратить свои деньги как вам вздумается.
Исключения, в сущности, ничем не лучше и не хуже кодов возвратов
Ну да, ну да.
ИМХО, главная проблема C++ных исключений в их высокой стоимости и последующей из нее непредсказуемости. Что поделать, исключения в C++ добавили тогда, когда большого опыта работы с исключениями еще ни у кого не было.
Ну, да, придется вместо MyType(...) писать MyType::Create(...). Велика ли потеря?
Да.
Следом за этим еще и перегрузка операторов идет в пешее эротическое.
В остальном тож самое)
Остается пожелать самому себе никогда не иметь дело с кодом, написанным такими экспертами.
Я бы даже сказал, есть много плюсов.
Говорите, говорите. Интернет, он все стерпит.
Если ничего не может внезапно сломаться в середине бизнес логики, потребителю библиотеки надо меньше думать.
facepalm.jpg
Если в середине бизнес-логики есть какой-нибудь условный vector::push_back, особенно если он скрыт под слоями абстракций, то ожидать, что ничего внезапно не сломается очень наивно. По меньшей мере.
Плюсом можно обмазаться в API слое всякими noexcept и получить какие-никакие плюсы к производительности)
Бездумное обмазывание noexcept -- прямой путь к внезапным падениям, а не к плюсам в производительности.
Могу понять когда исключения под запретом где-то в системщине (когда драйвера для ОС на C++ пишут) или в hard-real time. Но вне этих ниш обмазываться std::expected-ами и отказывать себе в нормальных полноценных конструкторах... Видимо, вам в C++ слишком мало боли, хотите еще.
А вот делать библиотеки, которые могут информировать о проблемах как посредством исключений, так и без них... Ну на любителя занятие. Пробовали в прошлом, не понравилось. Желающие могут взглянуть как это может выглядеть в исходниках Asio, например. И это Asio, которое лишь тонкая обертка над системным API, в котором С++ных исключений нет (я про системный API).
В режиме Debug программа работала, т.е. ошибки нет и не было. Тут если и есть ошибка, то только не моя.
Детский сад, младшая ясельная группа. Когда приложение работает в Debug-е, но падает в Release, то с вероятностью в 99% -- это баг в программе, а не в компиляторе. Особенно в многопотоке, где время работы конкретных кусков кода критически важно при обращениях к разделяемым данным. В Debug-е код работает в разы медленнее и "времянка" (есть такой старый термин) распределяется совсем не так, как в Release. Из-за чего в Release проявляются такие фокусы, до которых не сразу и додумаешься.
Блин, это прописные истины, это грабли, по которым оттаптываются все, кто хоть мало-мальски имел дело с многопоточностью.
Так как автор хорошей библиотеки всегда должен держать в уме сценарий использования в среде с отключёнными исключениями.
Только вот это огромный геморрой (чтобы библиотека могла работать и так, и так). Поэтому нахер -- кому нужны условия без исключений, тот пусть ищет библиотеку без исключений или пишет такую библиотеку сам.
Т.е. ошибка ушла, словно и не было. И для меня это осталось загадкой до сих пор.
Т.е. вы совершили ошибку в многопоточном коде, найти ее не смогли, написали очередную графоманскую статью о том, как вы не можете в многопоточный код, но все равно позволяете себе иронизировать над "пот, боль и кровь"?
Тут проблема в том, что оптимизатор может "оптимизировать" этот код: while (!stop) {}
ЕМНИП, в C++ (именно в С++, а не в чистом Си) бесконечный цикл без выраженных побочных эффектов -- это UB. И компилятор может сотворить все, что ему захочется.
Т.е. когда все те волшебные пилюли, про которые вы тут рассказываете, не помогают вам же писать многопоточный код без багов, то вам остается только расставлять смайлики и неумно шутить про "заминировано"?
Я, надеюсь, не похож на «мазохиста», терпящего «пот, боль и кровь» многопоточности (см. обсуждение статьи [7]).
Во-первых, вы искажаете смысл исходной цитаты, а именно "голая многопоточность -- это пот, боль и кровь." Т.е. не многопоточность вообще, а многопоточность на базе самых низкоуровневых примитивов, от atomic-ов и на коленке склепанных самостоятельно lock-free структур до semaphores, mutexes, events и condition variables. К счастью, есть более высокоуровневые подходы, очень сильно (я бы даже сказал драматически) упрощающие многопоточное программирование (но это обходится далеко не бесплатно).
Во-вторых, есть другой термин для обозначения человека, рассуждающего о вещах, в которых он не разбирается.
параллельное программирование – это далеко не про скорость. Скорость – лишь ее побочный эффект.
Рассуждения о плохости неудачности дизайна std::filesystem выглядят пустопорожними, потому что нет примеров того, как это должно было бы выглядеть по мнению автора статьи.
На мой рабоче-крестьянский взгляд exception safety означает не отсутствие исключений, а отсутствие проблем при возникновении исключений. В данной статье показан конструктор копирования DynamicArray, который не обеспечивает никаких гарантий exception safety:
Любопытно, что С++ позволяет сделать перегрузку метода для случая
const &&, что-то вроде:И вот если есть такая перегрузка, то std::move для константного объекта может иметь смысл.
Простая демонстрация: https://godbolt.org/z/MW8dMKvvK
Где это может пригодиться на практике лучше не спрашивать :)
Но с точки зрения возможности получить
const &&у std::move для константного объекта есть своя логика.Да уж... Столько хорошей информации и правильных слов в самой статье, а потом хоба! И реализация DynamicArray в которой конструктор копирования не exception safe :(((
PS. Поскольку DynamicArray -- это всего лишь демонстрация, то придираться к тому, что он поддерживает только те T, которые являются DefaultConstructible, нет смысла.
Пытаюсь оглянуться назад в 1995-й год, когда шаблоны начали появляться в доступных мне компиляторах... Да ведь они и тогда выглядели ну прям киллер-фичей, которой больше нигде не было. Из более-менее близкого к тогдашнему мейнстриму вспоминается разве что Ada со своим обобщенным программированием, но в Ada тогда еще не было ООП. А в C++ шаблоны были и для функций, и для классов, и даже для отдельных методов класса.
А уж сколько кода на шаблонах было написано до принятия С++11... Как-то сложно представить себе что все это было сделано на "неполезном" инструменте.
Да, когда исключения бросаются, то они могут дать просадку производительности на порядок, а то и на два. Кроме того, заранее неизвестно, сколько именно займет обработка исключения. Поэтому исключения под запретом в real-time. А это ведет к сегментированию в C++ (т.е. есть ниши где исключения под запретом, а есть где нет, и эти ниши сложно пересечь).
Я к тому, что если бы исключения были бы сделаны иначе (например, как в Eiffel) и были бы более дешевыми при использовании, такой проблемы с сегментированием в C++, возможно, не было бы.
Саттер несколько лет назад пытался продвинуть новый механизм для исключений. Но не взлетело до сих пор.
Бывает. Но тут можно и другую аналогию привести: так ли часто парашютистам нужен запасной парашют? И если он нужен не часто, то есть ли смысл от него отказаться совсем.
lavrov.jpg
При чем здесь MyType::ToString? Каким боком этот ваш "совет" поможет в DSL-естроении (например, вот таком)?
Т.е. вы пишите библиотеки, которые в каких-то местах работают, а в каких-то нет?
Контраргумент, которого вы, вероятно, не поняли, состоял в том, что если ваш код (например, ваша библиотека) использует чужой код, в котором исключения возможны (например, виде
std::bad_allocкоторый может вылететь изpush_back), то рассуждения о том, чтобы библиотека сама не бросала исключений становятся, скорее, росказнями, чем рассуждениями.Мой код, как правило, базируется на куче чужого кода.
Почему Google не использует у себя исключений уже многократно обсуждалось. А тем, кто не в курсе, можно попробовать прочитать соответствующий раздел из Google Code Style. С признанием того, что у исключений таки больше преимуществ. Только вот Google теперь дешевле продолжать писать без них.
Кроме того, далеко не у всех есть бюджеты Google. Если вы можете себе позволить писать больше менее надежного кода -- OK, можете извращаться как хотите, ваше право тратить свои деньги как вам вздумается.
Вы еще и диагнозы через Интернет ставите?
Видимо, в попытке объяснить простые вещи.
Ну да, ну да.
ИМХО, главная проблема C++ных исключений в их высокой стоимости и последующей из нее непредсказуемости. Что поделать, исключения в C++ добавили тогда, когда большого опыта работы с исключениями еще ни у кого не было.
Да.
Следом за этим еще и перегрузка операторов идет в пешее эротическое.
Остается пожелать самому себе никогда не иметь дело с кодом, написанным такими экспертами.
Говорите, говорите. Интернет, он все стерпит.
facepalm.jpg
Если в середине бизнес-логики есть какой-нибудь условный vector::push_back, особенно если он скрыт под слоями абстракций, то ожидать, что ничего внезапно не сломается очень наивно. По меньшей мере.
Бездумное обмазывание noexcept -- прямой путь к внезапным падениям, а не к плюсам в производительности.
Так можно и без C++ обойтись, но зачем?
Могу понять когда исключения под запретом где-то в системщине (когда драйвера для ОС на C++ пишут) или в hard-real time. Но вне этих ниш обмазываться std::expected-ами и отказывать себе в нормальных полноценных конструкторах... Видимо, вам в C++ слишком мало боли, хотите еще.
А вот делать библиотеки, которые могут информировать о проблемах как посредством исключений, так и без них... Ну на любителя занятие. Пробовали в прошлом, не понравилось. Желающие могут взглянуть как это может выглядеть в исходниках Asio, например. И это Asio, которое лишь тонкая обертка над системным API, в котором С++ных исключений нет (я про системный API).
lavrov.jpg
Разъяснять в стиле: "И для меня это осталось загадкой до сих пор."
Ну вперед.
Для многих практикующих C++ников стандарт C++26 еще не скоро станет обыденной реальностью.
Детский сад, младшая ясельная группа. Когда приложение работает в Debug-е, но падает в Release, то с вероятностью в 99% -- это баг в программе, а не в компиляторе. Особенно в многопотоке, где время работы конкретных кусков кода критически важно при обращениях к разделяемым данным. В Debug-е код работает в разы медленнее и "времянка" (есть такой старый термин) распределяется совсем не так, как в Release. Из-за чего в Release проявляются такие фокусы, до которых не сразу и додумаешься.
Блин, это прописные истины, это грабли, по которым оттаптываются все, кто хоть мало-мальски имел дело с многопоточностью.
Компилятор не видит изменения для stop и считает, что выражение всегда истинно.
Только вот это огромный геморрой (чтобы библиотека могла работать и так, и так). Поэтому нахер -- кому нужны условия без исключений, тот пусть ищет библиотеку без исключений или пишет такую библиотеку сам.
Т.е. вы совершили ошибку в многопоточном коде, найти ее не смогли, написали очередную графоманскую статью о том, как вы не можете в многопоточный код, но все равно позволяете себе иронизировать над "пот, боль и кровь"?
ЕМНИП, в C++ (именно в С++, а не в чистом Си) бесконечный цикл без выраженных побочных эффектов -- это UB. И компилятор может сотворить все, что ему захочется.
В ДНК
Т.е. когда все те волшебные пилюли, про которые вы тут рассказываете, не помогают вам же писать многопоточный код без багов, то вам остается только расставлять смайлики и неумно шутить про "заминировано"?
И как вы умудрились при такой-то любви и таких-то знаниях так вляпаться-то?
Во-первых, вы искажаете смысл исходной цитаты, а именно "голая многопоточность -- это пот, боль и кровь." Т.е. не многопоточность вообще, а многопоточность на базе самых низкоуровневых примитивов, от atomic-ов и на коленке склепанных самостоятельно lock-free структур до semaphores, mutexes, events и condition variables. К счастью, есть более высокоуровневые подходы, очень сильно (я бы даже сказал драматически) упрощающие многопоточное программирование (но это обходится далеко не бесплатно).
Во-вторых, есть другой термин для обозначения человека, рассуждающего о вещах, в которых он не разбирается.
А мужики-то и не знают...
Рассуждения о
плохостинеудачности дизайнаstd::filesystemвыглядят пустопорожними, потому что нет примеров того, как это должно было бы выглядеть по мнению автора статьи.