Каков наилучший способ реализации проверки утверждений в C ++?

StackOverflow https://stackoverflow.com/questions/179723

Вопрос

Под этим я подразумеваю, что мне нужно сделать, чтобы в моем коде были полезные утверждения?

MFC довольно прост, я просто использую ASSERT (что-то).

Каков способ, не связанный с MFC?

Редактировать: Можно ли остановить взлом assert в assert.c, а не в моем файле, который вызывал assert()?

Редактировать: В чем разница между <assert.h> & <cassert>?

Принятый Ответ: В этом посте множество отличных ответов, жаль, что я не могу принять более одного ответа (или кто-нибудь объединил бы их все).Итак, ответ присуждается Ферруччо (за первый ответ).

Это было полезно?

Решение

#include <cassert>

assert(something);

и для проверки во время компиляции статические утверждения Boost очень полезны:

#include <boost/static_assert.hpp>

BOOST_STATIC_ASSERT(sizeof(int) == 4);  // compile fails if ints aren't 32-bit

Другие советы

Это зависит от того, ищете ли вы что-то, что работает за пределами Visual C ++.Это также зависит от того, какой тип утверждения вы ищете.

Существует несколько типов утверждений:

  1. Препроцессор
    Эти утверждения выполняются с помощью директивы препроцессора #error
    Утверждения препроцессора оцениваются только на этапе предварительной обработки и, следовательно, бесполезны для таких вещей, как шаблоны.

  2. Время выполнения
    Эти утверждения выполняются с использованием assert() функция, определенная в <cassert>
    Утверждения во время выполнения оцениваются только во время выполнения.И, как указал BoltBait, не компилируются, если NDEBUG макрос был определен.

  3. Статический
    Эти утверждения выполняются, как вы сказали, с помощью ASSERT() макрос, но только в том случае, если вы используете MFC.Я не знаю другого способа выполнения статических утверждений, который является частью стандарта C / C ++, однако библиотека Boost предлагает другое решение: static_assert.
    Тот Самый static_assert функция из библиотеки Boost - это то, что будет добавлено в Стандарт C ++ 0x.

В качестве дополнительного предупреждения, assert() функция, предложенная Ферруччо, не имеет такого же поведения, как MFC ASSERT() макрос.Первое - это утверждение времени выполнения, в то время как второе - статическое утверждение.

Я надеюсь, что это поможет!

Утверждение (обычно) только для отладки

Проблема с " assert " заключается в том, что он обычно находится в отладочных двоичных файлах, и что некоторые разработчики используют их так, как если бы код все еще работал.

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

Но иногда (в большинстве случаев?) тесты не такие интенсивные, как хотелось бы. Я не буду говорить о старой работе, где нам приходилось кодировать до самой последней минуты (<я> не спрашиваю ... Иногда менеджеры просто ... хм ... ) ... Какой смысл утверждать, что вы добавляете код, который будет скомпилирован и передан клиенту как двоичный файл релиза в следующую минуту?

утверждать в (некоторых) реальных приложениях

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

Assert обнаружит и обработает ошибку только при отладочной сборке.

Поэтому мы добавили вместо этого макрос XXX_ASSERT, а также макрос XXX_RAISE_ERROR.

Макрос XXX_ASSERT будет делать то же самое, что и макрос ASSERT, но он будет встроен как в Debug, так и в Release. Его поведение (запись журнала, открытие окна сообщений, ничего не делать и т. Д.) Может контролироваться файлом .INI, а затем он прерывает / завершает работу приложения.

Это использовалось как:

bool doSomething(MyObject * p)
{
   // If p is NULL, then the app will abort/exit
   XXX_ASSERT((p != NULL), "Hey ! p is NULL !") ;

   // etc.
}
Макрос

XXX_RAISE_ERROR будет только " log " ошибка, но не будет пытаться справиться с этим. Это означает, что он может записать сообщение в файл и / или открыть MessageBox с сообщением, кнопкой для продолжения и другой для запуска сеанса отладки (согласно конфигурации файла .INI). Это использовалось как:

bool doSomething(MyObject * p)
{
   if(p == NULL)
   {
      // First, XXX_RAISE_ERROR will alert the user as configured in the INI file
      // perhaps even offering to open a debug session
      XXX_RAISE_ERROR("Hey ! p is NULL !") ;
      // here, you can handle the error as you wish
      // Than means allocating p, or throwing an exception, or
      // returning false, etc.
      // Whereas the XXX_ASSERT could simply crash.
   }

   // etc.
}

Через год после их появления в наших библиотеках используется только XXX_RAISE_ERROR. Конечно, его нельзя использовать в критических по времени частях приложения (для этого у нас есть XXX_RAISE_ERROR_DBG), но везде это хорошо. И факты того, что можно использовать любую предпочтительную обработку ошибок и то, что она может быть активирована по желанию, либо на компьютере разработчика, либо на тестере, либо даже на пользователе, весьма полезны.

Чтобы ответить на вопрос в вашей второй "правке":

< assert.h> - это заголовок C

< cassert> - это заголовок стандартной библиотеки C ++ ...обычно она включает в себя < утверждать.h>

Чтобы выполнить взлом внутри файла, который вызвал assert, вы можете использовать пользовательский макрос, который генерирует исключение или вызывает __debugbreak:

#define MYASSERT(EXPR, MSG) if (!(EXPR)) throw MSG;

Или:

#define MYASSERT(EXPR) if (!(EXPR)) __debugbreak();

Базовое использование Assert

#include <cassert>

/* Some code later */
assert( true );

Рекомендации по применению

Утверждения используются для идентификации состояния среды выполнения, которые должны быть истинными.В результате они компилируются в режиме выпуска.

Если у вас есть ситуация, когда вы хотите, чтобы assert всегда выполнялся, вы можете передать ему false .Например:

switch ( someVal ):
{
case 0:
case 1:
  break;
default:
  assert( false ); /* should never happen */
}

Также возможно передать сообщение через assert:

assert( !"This assert will always hit." );

Зрелые кодовые базы часто расширяют функциональность assert.Некоторые из распространенных расширений включают:

  • Переключение утверждений выполняется для каждого модуля, чтобы локализовать тестирование.
  • Создание дополнительного макроса assert, который компилируется в большинстве отладочных сборок.Это желательно для кода, который вызывается очень часто (миллионы раз в секунду) и вряд ли будет некорректным.
  • Позволяет пользователям отключать выполненное в данный момент утверждение, все утверждения в модуле компиляции или все утверждения в кодовой базе.Это останавливает запуск доброкачественных утверждений, создавая непригодные для использования сборки.

Microsoft CRT утверждает

#include <crtdbg.h>
#include <sstream>
...
// displays nondescript message box when x <= 42
_ASSERT(x > 42);
// displays message box with "x > 42" message when x <= 42
_ASSERTE(x > 42);
// displays message box with computed message "x is ...!" when x <= 42
_ASSERT_EXPR(
   x > 42, (std::stringstream() << L"x is " << x << L"!").str().c_str());

Существует более продвинутая библиотека с открытым исходным кодом под названием ModAssert, которая имеет утверждения, которые работают как на Visual C ++, так и на gcc. Вероятно, также на других компиляторах, не знаю наверняка. Это займет некоторое время, чтобы выучить это, но если вы хотите хорошие утверждения, которые не зависят от MFC, посмотрите на них. Он находится по адресу http://sourceforge.net/projects/modassert/

используйте intellisense, чтобы открыть его в visual studio (щелкните правой кнопкой мыши)

// cassert standard header
#include <yvals.h>
#include <assert.h>

yvals.h - это материал для Windows. поэтому, что касается самого assert (), два способа его включения идентичны. рекомендуется использовать <cxxx>, потому что зачастую это не так просто (перенос пространства имен и, возможно, другое волшебство)

Это перерыв на сайте звонящего для меня ...

вот статья , объясняющая, почему вы не хотите писать этот макрос самостоятельно.

Вот моя последняя итерация средства утверждения в C ++: http://pempek.net/articles/2013/11/17/cross-platform-cpp-assertion-library/

Это библиотека из двух файлов, которую вы можете легко добавить в свой проект.

Чтобы ответить на третий вопрос автора: первая причина, по которой мы используем " cassert " вместо " assert.h " Это связано с тем, что в случае C ++ допускается тот факт, что компилятор C ++ может хранить описания функций не в файлах кода, а в DLL или в самом компиляторе. Во-вторых, в функции могут быть внесены незначительные изменения, чтобы облегчить различия между C и C ++, как в настоящее время, так и в будущем. Поскольку assert.h является библиотекой C, предпочтение отдается использованию & Quot; cassert & Quot; в то время как в C ++.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top