assertions


Concept: Assertions

Assertions are a powerful debugging tool in C++ that help developers catch logical errors and validate assumptions in their code. The assert macro, defined in the <cassert> header, is used to test if a given condition is true. If the condition is false, the program terminates and provides diagnostic information. Assertions are typically used during development and testing phases and can be disabled in release builds for performance reasons.

Example 1: Basic Usage of assert

#include <cassert>
#include <iostream>

int divide(int a, int b) {
    assert(b != 0 && "Divisor cannot be zero");
    return a / b;
}

int main() {
    std::cout << "Result: " << divide(10, 2) << std::endl;
    std::cout << "Result: " << divide(10, 0) << std::endl;
    return 0;
}

Explanation

In this example, we use assert to check if the divisor is not zero before performing division. If the assertion fails (i.e., when b is 0), the program will terminate with an error message.

Example 2: Using assert in a Class

#include <cassert>
#include <iostream>
#include <vector>

class SafeArray {
private:
    std::vector<int> data;

public:
    void push_back(int value) {
        data.push_back(value);
    }

    int& at(size_t index) {
        assert(index < data.size() && "Index out of bounds");
        return data[index];
    }
};

int main() {
    SafeArray arr;
    arr.push_back(10);
    arr.push_back(20);

    std::cout << "Element at index 1: " << arr.at(1) << std::endl;
    std::cout << "Element at index 2: " << arr.at(2) << std::endl;

    return 0;
}

Explanation

This example demonstrates the use of assert in a class method to ensure that array access is within bounds.

Example 3: Static Assertions

#include <cassert>
#include <iostream>
#include <type_traits>

template <typename T>
class NumericOperations {
public:
    static_assert(std::is_arithmetic<T>::value, "T must be an arithmetic type");

    T add(T a, T b) {
        return a + b;
    }

    T subtract(T a, T b) {
        return a - b;
    }
};

int main() {
    NumericOperations<int> intOps;
    std::cout << "5 + 3 = " << intOps.add(5, 3) << std::endl;

    NumericOperations<double> doubleOps;
    std::cout << "5.5 - 3.2 = " << doubleOps.subtract(5.5, 3.2) << std::endl;

    // This will cause a compile-time error:
    // NumericOperations<std::string> stringOps;

    return 0;
}

Explanation

This example showcases the use of static_assert, which is evaluated at compile-time:

Additional Considerations

  1. NDEBUG Macro: Assertions can be disabled by defining the NDEBUG macro before including <cassert>. This is often done in release builds for performance reasons.

  2. Custom Assertions: You can create custom assertion macros for more specific debugging needs, such as logging or handling exceptions.

  3. Performance Impact: While assertions are valuable for debugging, they can impact performance if overused, especially in performance-critical sections of code.

Summary

Assertions in C++ are a crucial tool for developers to catch logical errors and validate assumptions in their code. The assert macro provides a simple way to check conditions at runtime, while static_assert allows for compile-time checks. By using assertions effectively, developers can improve code quality, catch bugs early in the development process, and make their assumptions explicit. However, it's important to use assertions judiciously and consider their performance impact, especially in release builds.

Related

Previous Page | Course Schedule | Course Content