nodiscard c что это

Как пользоваться атрибутами из C++17

nodiscard c что это. Смотреть фото nodiscard c что это. Смотреть картинку nodiscard c что это. Картинка про nodiscard c что это. Фото nodiscard c что это

Jun 27, 2017 · 3 min read

Каждый атрибут попадает в стандарт отдельно. Атрибут [[deprecated]] (“устарело”) был стандартизирован в C++14, хотя в виде нестандартных расширений он был доступен в GCC, CLang и Visual C++ намного раньше. Если вы прячете атрибут за макросом, то для написания переносимого кода следует использовать простую форму атрибута, не принимающую аргументом строку с описанием причины, почему API устарел.

Новые атрибуты в C++17

В C++17 в стандарт попали три новых атрибута, которые позволяют управлять появлением различных предупреждений компилятора.

К сожалению, стандарт C++17 на момент написания ещё только начали внедрять. Пройдут годы, прежде чем большинство программистов сможет свободно использовать атрибуты в production.

Обнаружение атрибутов

Применение атрибута nodiscard

Указать атрибут nodiscard можно в объявлении функции:

Однако, если вы используете собственный класс для кодов ошибок, то вы можете указать атрибут только один раз в определении класса.

Это особенно полезно при включённой опции “warnings as errors” или при регулярной проверке отсутствия предупреждений на билдсервере. Вы ещё при комплиляции проверяете, что у вас имеется обработка ошибок.

Атрибут nodiscard был стандартизирован в C++17, но ещё до этого существовал под именем gnu::warn_unused_result в компиляторах GCC с давних времён и Clang с версии 3.6. Используя механизм обнаружения атрибутов, вы можете объявить макрос, добавляющий атрибут nodiscard:

Применение атрибута fallthrough

Заметим, что атрибут fallthrough должен быть внутри пустой инструкции, располагающейся непосредственно перед следующим case

Применение атрибута maybe_unused

Цель атрибута maybe_unused — погасить предупреждения от отладочных переменных. Такое решение замещает старые, менее очевидные для новичков и более многословные решения.

Атрибуты из C++11 и C++14

В предыдущих версиях стандарта уже было внесено несколько атрибутов, но они не получили широкого распространения, видимо, из-за отсутствия поддержки в определённых компиляторах и малого числа атрибутов. Но теперь, с выходом C++17, эти атрибуты можно и нужно использовать чаще.

Заключение

Источник

Атрибуты в C++

Стандарт C++ определяет общий набор атрибутов. Он также позволяет поставщикам компиляторов определять собственные атрибуты в пространстве имен, характерном для конкретного поставщика. Однако компиляторы необходимы только для распознавания атрибутов, определенных в стандарте.

Visual Studio 2017 версии 15,3 и более поздних версий (доступно в и более поздних версиях): в области списка атрибутов можно указать пространство имен для всех имен одним знаком using :

Стандартные атрибуты C++

В C++ 11 атрибуты предоставляют стандартизированный способ комментирования конструкций C++ (включая классы, функции, переменные и блоки) с дополнительными сведениями. Атрибуты могут быть или не зависят от поставщика. Компилятор может использовать эти сведения для создания информационных сообщений или для применения специальной логики при компиляции кода с атрибутом. Компилятор игнорирует все нераспознаваемые атрибуты, что означает, что вы не можете определить собственные настраиваемые атрибуты с помощью этого синтаксиса. Атрибуты заключены в двойные квадратные скобки:

[[noreturn]] Указывает, что функция никогда не возвращает значение; Иными словами, всегда возникает исключение. Компилятор может настроить правила компиляции для [[noreturn]] сущностей.

[[carries_dependency]] Указывает, что функция распространяет упорядочение зависимостей данных для синхронизации потоков. Атрибут можно применить к одному или нескольким параметрам, чтобы указать, что переданный аргумент несет зависимость в тело функции. Атрибут может применяться к самой функции, чтобы указать, что возвращаемое значение несет зависимость от функции. Компилятор может использовать эти сведения для создания более эффективного кода.

[[deprecated]] [[deprecated]] указывает, что функция не предназначена для использования. Кроме того, он может не существовать в будущих версиях интерфейса библиотеки. Компилятор может использовать этот атрибут для создания информационного сообщения, когда клиентский код пытается вызвать функцию. [[deprecated]] может применяться к объявлению класса, typedef-Name, переменной, нестатическому элементу данных, функции, пространству имен, перечислению, перечислителю или специализации шаблона.

[[fallthrough]] [[fallthrough]] (доступно в /std:c++17 и более поздних версиях). [[fallthrough]] Атрибут может использоваться в контексте switch инструкций в качестве указания компилятору (или любому пользователю, читающему код), который предназначен для fallthrough. Компилятор Microsoft C++ в настоящее время не предупреждает о поведении fallthrough, поэтому этот атрибут не влияет на поведение компилятора.

[[nodiscard]] [[nodiscard]] версий (доступна в /std:c++17 и более поздних версиях). Указывает, что возвращаемое значение функции не предназначено для удаления. Вызывает предупреждение порог предупреждения c4834, как показано в следующем примере:

[[maybe_unused]] [[maybe_unused]] версий (доступна в /std:c++17 и более поздних версиях). Указывает, что переменные, функции, классы, typedef, нестатические элементы данных, перечисления или специализацию шаблона могут быть намеренно не использованы. Компилятор не выдает предупреждение, если помеченная сущностью [[maybe_unused]] не используется. Сущность, объявленная без атрибута, может быть впоследствии повторно объявлена с атрибутом и наоборот. Сущность считается помеченной после первого объявления, помеченного как » проанализировано», и для оставшейся части текущего блока преобразования.

Атрибуты, относящиеся к Microsoft

[[gsl::suppress(rules)]] Этот атрибут, предназначенный для Microsoft, используется для подавления предупреждений от тех, которые применяют правила [[gsl::suppress(rules)]] в коде. Например, рассмотрим следующий фрагмент кода:

В этом примере возникают следующие предупреждения:

26494 (тип правило 5: всегда инициализировать объект.)

26485 (ограничивающее правило 3: нет массива для Decay указателя.)

26481 (правило границы 1: не используйте арифметические действия с указателями. Вместо этого используйте Span.)

Первые два предупреждения срабатывают при компиляции этого кода с установленным и активируемым средством анализа кода CppCoreCheck. Но третье предупреждение не срабатывает из-за атрибута. Вы можете подавить весь профиль границ, записав его [[gsl::suppress(bounds)]] без включения определенного номера правила. C++ Core Guidelines предназначены для помощи в написании лучшего и безопасного кода. Атрибут подавлять упрощает отключение предупреждений, когда они не нужны.

Источник

В чем причина не использования C ++ 17 [[nodiscard]] почти везде в новом коде?

И не является ли одним из принципов проектирования самого C ++, что компилятор должен улавливать как можно больше ошибок?

Если да, то почему бы не добавить [[nodiscard]] в свой собственный, не устаревший код почти для каждой функции void и почти для каждого класса тип?

Как я уже слышал об обсуждениях этой возможности в стандартных предложениях, блогах, вопросах переполнения стека или в другом месте в Интернете, я должен что-то пропускать.

Почему такая механика не имеет смысла в новом коде на C ++? Является ли многословие единственной причиной не использовать [[nodiscard]] почти везде?

3 ответа

В новом коде, который не должен быть совместим со старыми стандартами, используйте этот атрибут везде, где это разумно. Но для C ++ [[nodiscard]] делает плохой по умолчанию. Вы предлагаете:

Казалось бы гораздо более естественным заставить компиляторы сообщать об отброшенных значениях возврата по умолчанию, за исключением нескольких других случаев, когда вы отмечаете свое намерение.

Это может привести к тому, что существующий, правильный код испустит множество предупреждений. Хотя такое изменение можно было бы технически считать совместимым с обратной связью, поскольку любой существующий код все еще успешно компилируется, это было бы огромным изменением семантики на практике.

Атрибут [[nodiscard]] наиболее полезен в двух случаях:

, если функция не имеет эффектов за пределами возврата некоторого результата, т. е. является чистой. Если результат не используется, вызов, безусловно, бесполезен. С другой стороны, отказ от результата не был бы неправильным.

, если необходимо проверить возвращаемое значение, например. для C-подобного интерфейса, который возвращает коды ошибок вместо метания. Это основной вариант использования. Для идиоматических C ++ это будет довольно редко.

Эти два случая оставляют огромное пространство нечистых функций, которые возвращают значение, когда такое предупреждение вводит в заблуждение. Например:

Обратите внимание, что в некоторых случаях копия должна быть сделана в любом случае, поэтому благодаря возврату RVO копия будет бесплатной.

Эти примеры демонстрируют, что создание идиоматического кода кода на C ++ без предупреждений под языком «C ++ 17 с nodiscard по умолчанию» было бы довольно утомительным.

Возможно, проблема здесь не в изменении семантики, а в том, что функции каждого стандарта C ++ применимы к области для каждой компиляции, а не к области для каждого файла. Если /когда какой-либо будущий стандарт C ++ удаляется из файлов заголовков, такое изменение будет более реалистичным.

Дополнительные [[nodiscard]] обычаи

Примеры Canonical включают возвращаемое значение std :: async, где игнорирование возвращаемого значения означает отсутствие асинхронности вообще и возвращаемое значение пустой () функции контейнера, где люди иногда путают empty () и clear (), и мы не хотим, чтобы они думали, что вызов empty () имеет побочные эффекты, если они назовут это по ошибке.

[[nodiscard]] Значение подразумевается для ресурсов, требующих функции

Документация Visual Studio по C6031 указывает, что значение [[nodiscard]] подразумевается для ресурсов, требующих функций, таких как диск, сеть или память.

Пример

Вызывающий должен всегда проверять возвращаемое значение и обрабатывать ошибки соответственно.

extended [[nodiscard]] : должен проверить результат

_Must_inspect_result_ аннотированное возвращаемое значение должно быть ниже проверено или предупреждение.

«Инспекция» включает в себя: используется ли она в условном выражении, назначается выходному параметру или глобальному или передается как параметр.

Пример

В некоторых редких случаях возвращаемое значение намеренно не используется. Наиболее распространенным из этих случаев является то, что длина строки возвращается, но фактически не используется до того, как будет выполнен другой тест.

Мои мысли: [[maybe_noinspect]]

Так как можно различать два типа [[nodiscard]] :

Пример

Причины я бы не [[nodiscard]] почти везде:

Теперь, если вы сделали это по умолчанию, вы заставили бы всех разработчиков библиотек заставить всех своих пользователей не возвращать возвращаемые значения. Это было бы ужасно. Или вы заставляете их добавлять [[maydiscard]] в бесчисленное множество функций, что также является ужасным.

Источник

Восемь возможностей C++17, которые должен применять каждый разработчик

Мы поговорим о восьми удобных изменениях, которые влияют на ваш повседневный код. Четыре изменения касаются самого языка, а ещё четыре — его стандартной библиотеки.

Благодарности

Некоторые примеры я брал из докладов на конференциях Russian C++ User Group — за это огромное спасибо её организаторам и докладчикам! Я брал примеры из:

1. Декомпозиция при объявлении (англ. structural bindings)

В C++17 есть ограничения декомпозиции при объявлении:

Пример декомпозиции с try_emplace и декомпозиции key-value при обходе map:

2. Автоматический вывод параметров шаблонов

Вы можете создавать свои подсказки для автоматического вывода параметров шаблона: см. Automatic_deduction_guides

Интересная особенность: конструктор из initializer_list<> пропускается для списка из одного элемента. Для некоторых JSON библиотек (таких как json_spirit) это может оказаться фатальным. Не играйтесь с рекурсивными типами и контейнерами STL!

3. Объявление вложенных пространств имён

Избегайте вложенности пространств имён, а если не избежать, то объявляйте их так:

4. Атрибуты nodiscard, fallthrough, maybe_unused

Более подробно об атрибутах рассказано в статье Как пользоваться атрибутами из C++17. Здесь будут краткие выдержки.

В C++ приходится добавлять break после каждого case в конструкции switch, и об этом легко забыть даже опытному разработчику. На помощь приходит атрибут fallthrough, который можно приклеить к пустой инструкции. Фактически атрибут приклеивается к case, следующему за пустой инструкцией.

В проектах с высокими требованиями к производительности могут практиковать отказ от выброса исключений (по крайней мере в некоторых компонентах). В таких случаях об ошибке выполнения операции сообщает код возврата, возвращённый из функции. Однако, очень легко забыть проверить этот код.

Если вы используете, например, свой класс ошибок, то вы можете указать атрибут единожды в его объявлении.

Иногда программисты создают переменную, используемую только в отладочной версии для хранения кода ошибки вызванной функции. Возможно, это просто ошибка дизайна кода, и возвращаемое значение следовало обрабатывать всегда. Тем не менее:

5. Класс string_view для параметров-строк

Подробнее о том, почему string_view лучше всего применять только для параметров, читайте в статье std::string_view конструируется из временных экземпляров строк

Класс string_view хорош тем, что он легко конструируется и из std::string и из const char* без дополнительного выделения памяти. А ещё он имеет поддержку constexpr и повторяет интерфейс std::string. Но есть минус: для string_view не гарантируется наличие нулевого символа на конце.

6. Классы optional и variant

Применение optional<> и variant<> настолько широко, что я даже не буду пытаться полностью описать их в этой статье. Ключевые правила:

Пример кода с optional:

Пример кода с variant: здесь мы используем variant для хранения одного из нескольких состояний в случае, когда разные состояния могут иметь разные данные

Преимущество variant в его подходе к управлению памяти: данные хранятся в полях значения типа variant без дополнительных выделений памяти. Это делает размер типа variant зависимым от типов, входящих в его состав. Так может выглядеть таблица размеров на 32-битных процессорах (но это неточно):

nodiscard c что это. Смотреть фото nodiscard c что это. Смотреть картинку nodiscard c что это. Картинка про nodiscard c что это. Фото nodiscard c что это

7. Используйте функции std::size, std::data, std::begin, std::end

Может быть, для манипуляций с байтами лучше опираться на библиотеку GSL (C++ Core Guidelines Support Library).

8. Используйте std::filesystem

Чем плох boost::filesystem? Оказывается, у него есть несколько проблем дизайна:

Любой опытный программист знает о разнице в обработке путей между Windows и UNIX-системами:

Конечно же filesystem абстрагируется от подобных различий и позволяет легко работать как с платформо-зависимыми строками, так и с универсальным UTF-8:

Бонусное правило: прекратите переизобретать clamp, int_to_string и string_to_int

Функция std::clamp дополняет функции min и max. Она обрезает значение и сверху, и снизу. Аналогичная функция boost::clamp доступна в более ранних версиях C++.

Правило «не переизобретайте clamp» можно обобщить: в любом крупном проекте избегайте дублирования маленьких функции и выражений для округлений, обрезаний значений и т.п. — просто один раз добавьте это в свою библиотеку.

Аналогичное правило работает для задач обработки строк. У вас есть своя маленькая библиотека для строк и парсинга? В ней есть парсинг или форматирование чисел? Если есть, замените свою реализацию на вызовы to_chars и from_chars

Функции to_chars и from_chars поддерживают обработку ошибок. Они возвращают по два значения:

Поскольку в прикладном коде способ реакции на ошибку может различаться, следует помещать вызовы to_chars и from_chars внутрь своих библиотек и утилитных классов.

Источник

Атрибут nodiscard

Для примера написал такой класс:

nodiscard c что это. Смотреть фото nodiscard c что это. Смотреть картинку nodiscard c что это. Картинка про nodiscard c что это. Фото nodiscard c что это

nodiscard c что это. Смотреть фото nodiscard c что это. Смотреть картинку nodiscard c что это. Картинка про nodiscard c что это. Фото nodiscard c что это

1 ответ 1

На основании упомянутой в комментарии ссылки clang-tidy (используемый в CLion) предлагает добавить атрибут [[nodiscard]] к функции, т.к. функция подходит под перечисленный список условий. Суть условий в том, что видимое поведение функции может быть доступно только через возвращаемый результат. Если его проигнорировать, то такая функция будет выглядеть бесполезной. Чтобы этого избежать как раз существует упомянутый атрибут.

Подробнее о существующих атрибутах C++ можно почитать здесь.

nodiscard c что это. Смотреть фото nodiscard c что это. Смотреть картинку nodiscard c что это. Картинка про nodiscard c что это. Фото nodiscard c что это

Всё ещё ищете ответ? Посмотрите другие вопросы с метками c++ или задайте свой вопрос.

Связанные

Похожие

Подписаться на ленту

Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.

дизайн сайта / логотип © 2021 Stack Exchange Inc; материалы пользователей предоставляются на условиях лицензии cc by-sa. rev 2021.12.16.41042

Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *