7.12a — Assert and static_assert

Using a conditional statement to detect a violated assumption, along with printing an error message and terminating the program, is such a common response to problems that C++ provides a shortcut method for doing this. This shortcut is called an assert.

An assert statement is a preprocessor macro that evaluates a conditional expression at runtime. If the conditional expression is true, the assert statement does nothing. If the conditional expression evaluates to false, an error message is displayed and the program is terminated. This error message contains the conditional expression that failed, along with the name of the code file and the line number of the assert. This makes it very easy to tell not only what the problem was, but where in the code the problem occurred. This can help with debugging efforts immensely.

The assert functionality lives in the <cassert> header, and is often used both to check that the parameters passed to a function are valid, and to check that the return value of a function call is valid.

If the program calls getArrayValue(array, -3), the program prints the following message:

Assertion failed: index >= 0 && index <=9, file C:\\VCProjects\\Test.cpp, line 6

We encourage you to use assert statements liberally throughout your code.

Making your assert statements more descriptive

Sometimes assert expressions aren’t very descriptive. Consider the following statement:

If this assert is triggered, the assert will say:

Assertion failed: found, file C:\\VCProjects\\Test.cpp, line 34

What does this even mean? Clearly something wasn’t found, but what? You’d have to go look at the code to determine that.

Fortunately, there’s a little trick you can use to make your assert statements more descriptive. Simply add a C-style string description joined with a logical AND:

Here’s why this works: A C-style string always evaluates to boolean true. So if found is false, false && true = false. If found is true, true && true = true. Thus, logical AND-ing a string doesn’t impact the evaluation of the assert.

However, when the assert triggers, the string will be included in the assert message:

Assertion failed: found && "Car could not be found in database", file C:\\VCProjects\\Test.cpp, line 34

That gives you some additional context as to what went wrong.

NDEBUG and other considerations

The assert() function comes with a small performance cost that is incurred each time the assert condition is checked. Furthermore, asserts should (ideally) never be encountered in production code (because your code should already be thoroughly tested). Consequently, many developers prefer that asserts are only active in debug builds. C++ comes with a way to turn off asserts in production code: #define NDEBUG.

Some IDEs set NDEBUG by default as part of the project settings for release configurations. For example, in Visual Studio, the following preprocessor definitions are set at the project level: WIN32;NDEBUG;_CONSOLE. If you’re using Visual Studio and want your asserts to trigger in release builds, you’ll need to remove NDEBUG from this setting.

Do note that the exit() function and assert() function (if it triggers) terminate the program immediately, without a chance to do any further cleanup (e.g. close a file or database). Because of this, they should be used judiciously (only in cases where corruption isn’t likely to occur if the program terminates unexpectedly).


C++11 adds another type of assert called static_assert. static_assert takes the form


Unlike assert, which operates at runtime, static_assert is designed to operate at compile time, causing the compiler to error if the condition is not true. If the condition is false, the diagnostic message is printed.

Here’s an example of using static_assert to ensure types have a certain size:

On the author’s machine, when compiled, the compiler errors:

1>c:\consoleapplication1\main.cpp(19): error C2338: long must be 8 bytes

A few notes. Because static_assert is evaluated by the compiler, the conditional part of a static_assert must be able to be evaluated at compile time. Because static_assert is not evaluated at runtime, static_assert statements can also be placed anywhere in the code file (even in global space).

In C++11, a diagnostic message must be supplied as the second parameter. In C++17, providing a diagnostic message is optional.


C++ provides one more method for detecting and handling errors known as exception handling. The basic idea is that when an error occurs, the error is “thrown”. If the current function does not “catch” the error, the caller of the function has a chance to catch the error. If the caller does not catch the error, the caller’s caller has a chance to catch the error. The error progressively moves up the stack until it is either caught and handled, or until main() fails to handle the error. If nobody handles the error, the program typically terminates with an exception error.

Exception handling is an advanced C++ topic, and we cover it in much detail in chapter 14 of this tutorial.

7.13 -- Command line arguments
7.12 -- Handling errors, cerr and exit

33 comments to 7.12a — Assert and static_assert

  • Hi Alex!

    Just a heads up that contracts will be added in C++20. This lesson and at least the lessons using the Fraction class should be updated.

    • Alex

      Yup. Quite a few lessons will be impacted by C++20. If the modules functionality makes it in (and I hope it does), then pretty much every lesson will be impacted!

  • Alan

    Hi Alex,

    I was writing a piece of code which states

    While I was testing this piece of code by writing

    the console prints 'Assertion failed: invalidColor && ("Unrecognized color: " + color).c_str()'.

    What I want to ask is that, is there a way I can make the assert message alter based on different parameter contents in the function call?

    In this example, the ideal output on the console I would like to see is 'Assertion failed: invalidColor && "Unrecognized color: pink"'.

    • @assert is a compile-time macro, it's text content cannot be dynamically created.
      You can throw an exception (Chapter 14) instead

  • Davis

    Hey Alex,
    Could you explain why #define NDEBUG has to be written before #include <cassert> ?
    #define NDEBUG didn't work for my complier when I wrote it after #include <cassert>

    • nascardriver

      Hi Davis!

      When you include a file it's content is copied into the including file

      turns into

      Now, when you define NDEBUG after the include to <cassert>, the preprocessor has already checked whether or not it should enable asserts, that's why you need to define it before including <cassert>.

  • HI ALEX!
    Because static_assert is not evaluated at runtime, static_assert statements can also be placed anywhere in the code file (even in global space).


    • Alex

      It is so because that's how it was designed: The goal is to give programmers a way to flag things that you expect to be true at compile time rather than at runtime.

      For example, if your code has an assumption that integers are at least 4 bytes, previously you could assert this, but it wouldn't fail until you ran the program. With static_assert, you can now fail your program at compile time, saving you from compiling something that won't run anyway.

      Code execution always starts at the top of main() and then continues from there into whatever subfunctions are called. At no point is code in the global space ever executed.

      I don't understand your last question.

      • you said,"static_assert is evaluated at compile time so we can put it in global space comfortably". I want to ask what problem maybe caused if we put it in global space if it would  evaluate at runtime.

        • nascardriver

          Code outside of functions won't be executed at runtime. All code needs to be in a function of some sort. static_assert can be outside of functions and is executed at compile time.
          (There's also constexpr but I don't want to overcomplicate things)

            yes plz explain 'constexp' i saw it in 8.11 i don't know what does this keyword do?

            • nascardriver

              constexpr values and functions are evaluated at compile-time.
              constexpr value are covered in lesson 2.9, there's no tutorial for constexpr functions yet.
              You don't need to worry about constexpr functions just yet, learn the basics first.

  • David

    Typo: "If the program calls GetArrayValue(-3),"

    The function requires two arguments, but only one is provided. Also, the G is capitalized.

  • CrazyL

    Hello Alex,

    the first time I tried "#define NDEBUG" I used it after "#include <cassert>" and wondered why it didn't switch off all assert() afterwards:

    I guess that's a really stupid mistake to make, but to avoid confusion, it might be a good idea to change the snippet in "NDEBUG and other considerations" into the following lines:

    Anyway, thanks for the "to-the point" introduction of assert() and to use it effectively!

    • Aaron

      Hey there CrazyL!

      This answer was answered already before. But you might not have seen it, so here it comes!

      As said by nascardriver, when you include a file, the file is copied to the uncompiled code. The contents of cassert are something like this:

      So, before you define NDEBUG, the if statement is false, and assert, is defined.
      Don't credit me. Credit nascardriver.

  • James Ray

    "Exception handling is an advanced C++ topic, and we cover it in much detail in chapter 15 of this tutorial."

    It's  in chapter 14.

  • nikos-13

    Could you explain me the terms of "production code" and "debug builds" ?

  • Curiosity

    What Do You Mean By this? :-
    Because static_assert is not evaluated at run-time, static_assert statements can also be placed anywhere in the code file (even in global space).

    Plz Explain !
    And YES, I found that non-const vars don't work in static assertions.

    • Curiosity

      Oh Okay ! I saw that static_assert works in global space while assert doesn't.
      But Now, My question is that why run-time variables etc. don't work in global space?

      • Alex

        Global and static variables get initialized when the program starts up. Then execution begins at the top of main and continued to the bottom. Code in global space would never get executed.

    • Alex

      When code is executed at runtime, the execution path starts at the top of main() and continued to the bottom of main() (branching out for called functions). So for normal asserts, those need to be put inside a function that gets called in order to be executed at runtime.

      However, static_assert is evaluated by the compiler when it's compiling the program. This means static_assert can be placed anywhere in the program, even outside of functions, since it doesn't have to be within the path of execution.

      • Curiosity

        So It means that because compilation starts from the top of program(not from main()) that's why static assert is seen by it but because asserts are evaluated at run-time they are not seen as execution starts from the top of main()(not from the top of program)
        Tell Me If I'm Right !

  • C++ Learner

    can you explain what do you mean by this sentence? :)
    In C++11, a diagnostic message must be supplied as the second parameter(it is written just above "Exceptions")

    • Alex

      The diagnostic message is the second parameter provided to the static_assert function that gets printed if the condition isn't true. For example, "long must be 8 bytes" is a diagnostic message.

  • John

    I'm running the code below, but I don't get the message "Assertion failed: index >= 0 && index <=9, file...", rather, the program just crashes with the usual message box showing up. Is something wrong in the code?

    • Alex

      Nothing is wrong in the code. My best guess is that you're running your code with a release configuration, and that's setting NDEBUG, which turns assertions off. Try recompiling and running your code using a debug configuration instead.

      • John

        Ok, I found the problem, it’s compiler specific. MinGW is not directing the the diagnostic message to std::cout, but to a pop-up window. To see this pop up window the code has to be compiled with the mwindow switch, i.e. g++ -mwindow main.cpp, then it works as shown in the example.

Leave a Comment

Put all code inside code tags: [code]your code here[/code]