noexcept in C++
In this article, we will discuss the noexcept in C++ with its types, syntax, examples, and outputs.
In C++, noexcept is a contextual keyword that specifies that a function does not throw any exceptions. The noexcept keyword is typically used in two different contexts:
1. Function Specifier:
It is used to declare a function with a guarantee that it will not throw exceptions. The noexcept function specifier is placed after the parameter list and before the function body. It assures the caller and the compiler that the function will not throw exceptions.
2. Operator Specifier:
It declares that a specific operator will not throw exceptions. It is often used in conjunction with user-defined operator overloads.
Suppose you have a magic box (function) that can do something for you. Sometimes this magic box can have unexpected problems that need to be fixed. When that happens, it may throw out a "surprise" you didn't expect. But some magic boxes promise to avoid surprises and always work perfectly. These magic boxes are labeled with the unique word "noexcept". When you see this word on a magic box, it means you can trust it not to give you any surprises or problems. It's like a guarantee that it will be able to run smoothly and smoothly.
So, if you have a "noexcept" magic box, you know it will do its job smoothly and won't cause any trouble. You can rely on it to work as you expect every time you use it. This way, you can use it confidently without worrying about any surprises.
In programming, "noexcept" is like that label on the magic box that tells us that a specific part of the code won't throw any surprises or exceptions. It's helpful for programmers to understand how different parts of the program will behave and how to handle any issues that might come up. And just like in real life, it gives us peace of mind, knowing that some parts of our program are stable and won't create unexpected problems.
Syntax for the noexcept in C++:
It has the following syntax:
return_typefunction_name(parameters) noexcept {
// Function body
}
Example 1:
Let's take an example to demonstrate the working of the noexcept keyword in C++.
Code:
#include <iostream>
#include <stdexcept>
#include <limits>
#include<cmath>
using namespace std;
// A function that performs division and is marked as noexcept
double divide(double numerator, double denominator) noexcept {
if (denominator == 0.0) {
// Division by zero is not allowed, so we return NaN (Not a Number)
return numeric_limits<double>::quiet_NaN();
}
return numerator / denominator;
}
// A function that performs input validation and might throw an exception
void getInput(double& value) {
cout<< "Enter a non-zero number: ";
cin>> value;
if (value == 0.0) {
throw invalid_argument("Zero is not allowed as input.");
}
}
int main() {
double num1, num2;
try {
getInput(num1);
getInput(num2);
double result = divide(num1, num2);
if (isnan(result)) {
cout<< "Division by zero is not allowed." <<endl;
} else {
cout<< "Result of division: " << result <<endl;
}
} catch (const exception& e) {
cerr<< "Error: " <<e.what() <<endl;
}
return 0;
}
Output:
![noexcept in C++](https://static.tutorialandexample.com/cpp/noexcept-in-cpp1.png)
Explanation:
The code includes three standard C++ libraries: iostream, stdexcept, and limits. It also includes a math library to use the isnan() function.
The function divide(double numerator, double denominator) noexcept is defined to perform division. It is marked with noexcept, which means it guarantees not to throw any exceptions during its execution. If the denominator is 0, the function returns a special value called "Not a Number" (NaN) using numeric_limits<double>::quiet_NaN(), indicating that division by zero is not allowed. Otherwise, it returns the result of the division numerator/denominator.
The function getInput(double& value) is defined to take input from the user and validate it. It prompts the user to enter a value, reads it from the console using cin, and stores it in the value variable. If the user enters 0, the function throws an exception of type invalid_argument, indicating that 0 is not allowed as input.
In the main() function, two double variables (num1 and num2) are declared to store the input values. The try block is used to handle potential exceptions that may be thrown during input and division.
The getInput() function is called twice to get two non-zero numbers from the user, which are stored in num1 and num2. The divide() function is called with the user-provided numbers. If the result is NaN (indicating division by zero), it means the division was not allowed. Otherwise, the result of the division is printed.
If an exception occurs during input validation or division, the catch block will handle it. It catches any exception of type exception (or its subclasses) and prints an error message using cerr. After that, the program returns 0, indicating successful execution.
Overall, this program demonstrates a safe way of performing division by checking for zero input, handling exceptions properly, and using noexcept to provide information to the compiler and programmers about the expected behavior of the divide() function.
Example 2:
Let's take another example to demonstrate the working of the noexcept keyword in C++.
#include <iostream>
#include <stdexcept>
// A function that calculates the factorial of a positive integer and is marked asnoexcept
int factorial(int n) noexcept {
if (n < 0) {
// Factorial is not defined for negative numbers, so we return -1 to indicate an error
return -1;
}
// Base case: factorial of 0 is 1
if (n == 0) {
return 1;
}
// Recursive case: calculate factorial using recursion
return n * factorial(n - 1);
}
// A function that performs input validation and might throw an exception
void getPositiveInput(int& value) {
std::cout<< "Enter a positive integer: ";
std::cin>> value;
if (value < 0) {
throw std::invalid_argument("Negative numbers are not allowed.");
}
}
int main() {
int num;
try {
getPositiveInput(num);
int result = factorial(num);
if (result == -1) {
std::cout<< "Factorial is not defined for negative numbers." <<std::endl;
} else {
std::cout<< "Factorial of " <<num<< " is: " << result << std::endl;
}
} catch (const std::exception& e) {
std::cerr<< "Error: " <<e.what() << std::endl;
}
return 0;
}
Output:
![noexcept in C++](https://static.tutorialandexample.com/cpp/noexcept-in-cpp2.png)
Explanation:
In this example, we calculate the factorial of a positive integer entered by the user. This code uses the factorial() function, marked with noexcept to indicate that it does not throw any exceptions. It also includes a function named getPositiveInput() that takes care of user input validation and might throw an exception if the user provides a negative number.
The program includes two standard C++ libraries: iostream for input and output operations and except for handling exceptions. The factorial() function calculates the factorial of a positive integer. It takes an integer n as an input parameter and returns an integer as the result. The function is marked with noexcept to guarantee that it will not throw any exceptions during its execution.
Inside the factorial() function, there are three main cases:
- If the input n is negative (n < 0), the function returns -1 to indicate that factorial is not defined for negative numbers.
- If the input n is 0 (n == 0), the base case is reached, and the function returns one since the factorial of 0 is defined as 1.
- For positive integers (n > 0), the function recursively calls itself with n - 1 as the argument and multiplies the result with n. It continues until the base case is reached.
After that, the getPositiveInput() function is defined as getting input from the user and validating it. It takes an integer reference value as a parameter. The function prompts the user to enter a positive integer and reads the input using std::cin.
If the user enters a negative number (value < 0), the getPositiveInput() function throws an exception of type std::invalid_argument, indicating that negative numbers are not allowed as input.
In the main() function, an integer variable num is declared to store the user's input. The try block is used to handle potential exceptions that may be thrown during input and factorial calculation. The getPositiveInput() function is called to get a positive integer from the user, and the input is stored in the num variable.
The factorial() function is called with the user-provided number (num), and the result is stored in the result variable. If the factorial() function returns -1, it means the input was negative, and the code outputs a message saying that the factorial is not defined for negative numbers. If the factorial() function returns a valid result, the code prints the calculated factorial of the input number.
If an exception occurs during input validation or factorial calculation, the catch block will handle it. It catches any exception of type std::exception (or its subclasses) and prints an error message using std::cerr. After that, the program returns 0, indicating successful execution.
In summary, this C++ program calculates the user's factorial of a positive integer input. It takes care of negative inputs by using the noexcept specifier for the factorial function to guarantee that no exceptions are thrown during its execution. Additionally, it handles invalid inputs using exceptions and provides informative error messages to the user. The noexcept specifier ensures that the factorial function will execute safely without any unexpected surprises, providing better program stability and reliability.