Подтвердить что ты не робот

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

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

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

Какой путь не-MFC?

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

Изменить: Какая разница между <assert.h> и <cassert>?

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

4b9b3361

Ответ 1

#include <cassert>

assert(something);

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

#include <boost/static_assert.hpp>

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

Ответ 2

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

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

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

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

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

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

Надеюсь, это поможет!

Ответ 3

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

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

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

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

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

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

Assert будет определять и обрабатывать ошибку только при сборке отладки.

Итак, мы добавили макрос XXX_ASSERT, а также макрос XXX_RAISE_ERROR.

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

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

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 макрос будет только "регистрировать" ошибку, но не будет пытаться ее обработать. Это означает, что он может регистрировать сообщение в файле и/или открывать 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), но везде, это хорошо. И факты, которые могут использовать любую предпочтительную обработку ошибок и что ее можно активировать по своему усмотрению, либо на компьютере разработчика, либо на тесте, либо даже на пользователе, весьма полезны.

Ответ 4

Чтобы ответить на вопрос во втором "edit":

< assert.h > является заголовком C

<cassert> является заголовком стандартной библиотеки С++... он обычно включает < assert.h >

Ответ 5

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

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

Или:

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

Ответ 6

Основное использование подтверждения

#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, который компилируется в большинстве отладочных сборников. Это желательно для кода, который называется очень часто (миллионы раз в секунду) и вряд ли будет неправильным.
  • Разрешить пользователям отключать текущее утверждение, все утверждения в блоке компиляции или все утверждения в кодовой базе. Это останавливает нежелательные утверждения от срабатывания, создавая непригодные сборки.

Ответ 7

Конкретный CRT для Microsoft

#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());

Ответ 8

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

Ответ 9

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

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

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

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

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

Ответ 11

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