Skip to content

Commit 81252b8

Browse files
Merge pull request #4998 from MicrosoftDocs/main638469847285679828sync_temp
For protected branch, push strategy should use PR and merge to target branch method to work around git push error
2 parents b2fbe72 + 592254e commit 81252b8

File tree

2 files changed

+21
-30
lines changed

2 files changed

+21
-30
lines changed

docs/cpp/errors-and-exception-handling-modern-cpp.md

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
11
---
22
title: "Modern C++ best practices for exceptions and error handling"
33
description: "How Modern C++ supports exceptional programming styles over error codes."
4-
ms.date: 08/24/2020
4+
ms.date: 03/22/2024
55
ms.topic: "conceptual"
6-
ms.assetid: a6c111d0-24f9-4bbb-997d-3db4569761b7
76
---
87
# Modern C++ best practices for exceptions and error handling
98

109
In modern C++, in most scenarios, the preferred way to report and handle both logic errors and runtime errors is to use exceptions. It's especially true when the stack might contain several function calls between the function that detects the error, and the function that has the context to handle the error. Exceptions provide a formal, well-defined way for code that detects errors to pass the information up the call stack.
1110

1211
## Use exceptions for exceptional code
1312

14-
Program errors are often divided into two categories: Logic errors that are caused by programming mistakes, for example, an "index out of range" error. And, runtime errors that are beyond the control of programmer, for example, a "network service unavailable" error. In C-style programming and in COM, error reporting is managed either by returning a value that represents an error code or a status code for a particular function, or by setting a global variable that the caller may optionally retrieve after every function call to see whether errors were reported. For example, COM programming uses the HRESULT return value to communicate errors to the caller. And the Win32 API has the `GetLastError` function to retrieve the last error that was reported by the call stack. In both of these cases, it's up to the caller to recognize the code and respond to it appropriately. If the caller doesn't explicitly handle the error code, the program might crash without warning. Or, it might continue to execute using bad data and produce incorrect results.
13+
Program errors are often divided into two categories:
14+
- Logic errors caused by programming mistakes. For example, an "index out of range" error.
15+
- Runtime errors that are beyond the control of programmer. For example, a "network service unavailable" error.
16+
17+
In C-style programming and in COM, error reporting is managed either by returning a value that represents an error code or a status code for a particular function, or by setting a global variable that the caller may optionally retrieve after every function call to see whether errors were reported. For example, COM programming uses the `HRESULT` return value to communicate errors to the caller. And the Win32 API has the `GetLastError` function to retrieve the last error reported by the call stack. In both of these cases, it's up to the caller to recognize the code and respond to it appropriately. If the caller doesn't explicitly handle the error code, the program might crash without warning. Or, it might continue to execute using bad data and produce incorrect results.
1518

1619
Exceptions are preferred in modern C++ for the following reasons:
1720

1821
- An exception forces calling code to recognize an error condition and handle it. Unhandled exceptions stop program execution.
19-
2022
- An exception jumps to the point in the call stack that can handle the error. Intermediate functions can let the exception propagate. They don't have to coordinate with other layers.
21-
2223
- The exception stack-unwinding mechanism destroys all objects in scope after an exception is thrown, according to well-defined rules.
23-
2424
- An exception enables a clean separation between the code that detects the error and the code that handles the error.
2525

26-
The following simplified example shows the necessary syntax for throwing and catching exceptions in C++.
26+
The following simplified example shows the necessary syntax for throwing and catching exceptions in C++:
2727

2828
```cpp
2929
#include <stdexcept>
@@ -35,7 +35,9 @@ using namespace std;
3535
void MyFunc(int c)
3636
{
3737
if (c > numeric_limits< char> ::max())
38+
{
3839
throw invalid_argument("MyFunc argument too large.");
40+
}
3941
//...
4042
}
4143

@@ -56,33 +58,27 @@ int main()
5658
}
5759
```
5860
59-
Exceptions in C++ resemble ones in languages such as C# and Java. In the **`try`** block, if an exception is *thrown* it will be *caught* by the first associated **`catch`** block whose type matches that of the exception. In other words, execution jumps from the **`throw`** statement to the **`catch`** statement. If no usable catch block is found, `std::terminate` is invoked and the program exits. In C++, any type may be thrown; however, we recommend that you throw a type that derives directly or indirectly from `std::exception`. In the previous example, the exception type, [`invalid_argument`](../standard-library/invalid-argument-class.md), is defined in the standard library in the [`<stdexcept>`](../standard-library/stdexcept.md) header file. C++ doesn't provide or require a **`finally`** block to make sure all resources are released if an exception is thrown. The resource acquisition is initialization (RAII) idiom, which uses smart pointers, provides the required functionality for resource cleanup. For more information, see [How to: Design for exception safety](how-to-design-for-exception-safety.md). For information about the C++ stack-unwinding mechanism, see [Exceptions and stack unwinding](exceptions-and-stack-unwinding-in-cpp.md).
61+
Exceptions in C++ resemble ones in languages such as C# and Java. In the **`try`** block, if an exception is *thrown* it is *caught* by the first associated **`catch`** block whose type matches that of the exception. In other words, execution jumps from the **`throw`** statement to the **`catch`** statement. If no usable catch block is found, `std::terminate` is invoked and the program exits. In C++, any type may be thrown; however, we recommend that you throw a type that derives directly or indirectly from `std::exception`. In the previous example, the exception type, [`invalid_argument`](../standard-library/invalid-argument-class.md), is defined in the standard library in the [`<stdexcept>`](../standard-library/stdexcept.md) header file. C++ doesn't provide or require a **`finally`** block to make sure all resources are released if an exception is thrown. The resource acquisition is initialization (RAII) idiom, which uses smart pointers, provides the required functionality for resource cleanup. For more information, see [How to: Design for exception safety](how-to-design-for-exception-safety.md). For information about the C++ stack-unwinding mechanism, see [Exceptions and stack unwinding](exceptions-and-stack-unwinding-in-cpp.md).
6062
6163
## Basic guidelines
6264
6365
Robust error handling is challenging in any programming language. Although exceptions provide several features that support good error handling, they can't do all the work for you. To realize the benefits of the exception mechanism, keep exceptions in mind as you design your code.
6466
65-
- Use asserts to check for errors that should never occur. Use exceptions to check for errors that might occur, for example, errors in input validation on parameters of public functions. For more information, see the [Exceptions versus assertions](#exceptions_versus_assertions) section.
66-
67+
- Use asserts to check for conditions that should always be true or always be false. Use exceptions to check for errors that might occur, for example, errors in input validation on parameters of public functions. For more information, see the [Exceptions versus assertions](#exceptions_versus_assertions) section.
6768
- Use exceptions when the code that handles the error is separated from the code that detects the error by one or more intervening function calls. Consider whether to use error codes instead in performance-critical loops, when code that handles the error is tightly coupled to the code that detects it.
68-
69-
- For every function that might throw or propagate an exception, provide one of the three exception guarantees: the strong guarantee, the basic guarantee, or the nothrow (noexcept) guarantee. For more information, see [How to: Design for exception safety](how-to-design-for-exception-safety.md).
70-
69+
- For every function that might throw or propagate an exception, provide one of the three exception guarantees: the strong guarantee, the basic guarantee, or the nothrow (`noexcept`) guarantee. For more information, see [How to: Design for exception safety](how-to-design-for-exception-safety.md).
7170
- Throw exceptions by value, catch them by reference. Don't catch what you can't handle.
72-
7371
- Don't use exception specifications, which are deprecated in C++11. For more information, see the [Exception specifications and `noexcept`](#exception_specifications_and_noexcept) section.
74-
7572
- Use standard library exception types when they apply. Derive custom exception types from the [`exception` Class](../standard-library/exception-class.md) hierarchy.
76-
7773
- Don't allow exceptions to escape from destructors or memory-deallocation functions.
7874
7975
## Exceptions and performance
8076
81-
The exception mechanism has a minimal performance cost if no exception is thrown. If an exception is thrown, the cost of the stack traversal and unwinding is roughly comparable to the cost of a function call. Additional data structures are required to track the call stack after a **`try`** block is entered, and additional instructions are required to unwind the stack if an exception is thrown. However, in most scenarios, the cost in performance and memory footprint isn't significant. The adverse effect of exceptions on performance is likely to be significant only on memory-constrained systems. Or, in performance-critical loops, where an error is likely to occur regularly and there's tight coupling between the code to handle it and the code that reports it. In any case, it's impossible to know the actual cost of exceptions without profiling and measuring. Even in those rare cases when the cost is significant, you can weigh it against the increased correctness, easier maintainability, and other advantages that are provided by a well-designed exception policy.
77+
The exception mechanism has a minimal performance cost if no exception is thrown. If an exception is thrown, the cost of the stack traversal and unwinding is roughly comparable to the cost of a function call. Other data structures are required to track the call stack after a **`try`** block is entered, and more instructions are required to unwind the stack if an exception is thrown. However, in most scenarios, the cost in performance and memory footprint isn't significant. The adverse effect of exceptions on performance is likely to be significant only on memory-constrained systems. Or, in performance-critical loops, where an error is likely to occur regularly and there's tight coupling between the code to handle it and the code that reports it. In any case, it's impossible to know the actual cost of exceptions without profiling and measuring. Even in those rare cases when the cost is significant, you can weigh it against the increased correctness, easier maintainability, and other advantages that are provided by a well-designed exception policy.
8278
8379
## <a name="exceptions_versus_assertions"></a> Exceptions versus assertions
8480
85-
Exceptions and asserts are two distinct mechanisms for detecting run-time errors in a program. Use `assert` statements to test for conditions during development that should never be true if all your code is correct. There's no point in handling such an error by using an exception, because the error indicates that something in the code has to be fixed. It doesn't represent a condition that the program has to recover from at run time. An `assert` stops execution at the statement so that you can inspect the program state in the debugger. An exception continues execution from the first appropriate catch handler. Use exceptions to check error conditions that might occur at run time even if your code is correct, for example, "file not found" or "out of memory." Exceptions can handle these conditions, even if the recovery just outputs a message to a log and ends the program. Always check arguments to public functions by using exceptions. Even if your function is error-free, you might not have complete control over arguments that a user might pass to it.
81+
Exceptions and asserts are two distinct mechanisms for detecting run-time errors in a program. Use `assert` statements to test for conditions during development that should always be true or always be false if all your code is correct. There's no point in handling such an error by using an exception, because the error indicates that something in the code has to be fixed. It doesn't represent a condition that the program has to recover from at run time. An `assert` stops execution at the statement so that you can inspect the program state in the debugger. An exception continues execution from the first appropriate catch handler. Use exceptions to check error conditions that might occur at run time even if your code is correct, for example, "file not found" or "out of memory." Exceptions can handle these conditions, even if the recovery just outputs a message to a log and ends the program. Always check arguments to public functions by using exceptions. Even if your function is error-free, you might not have complete control over arguments that a user might pass to it.
8682
8783
## C++ exceptions versus Windows SEH exceptions
8884
@@ -96,6 +92,6 @@ Exception specifications were introduced in C++ as a way to specify the exceptio
9692
9793
## See also
9894
99-
[How to: Interface between exceptional and non-exceptional code](../cpp/how-to-interface-between-exceptional-and-non-exceptional-code.md)<br/>
100-
[C++ language reference](../cpp/cpp-language-reference.md)<br/>
95+
[How to: Interface between exceptional and non-exceptional code](../cpp/how-to-interface-between-exceptional-and-non-exceptional-code.md)\
96+
[C++ language reference](../cpp/cpp-language-reference.md)\
10197
[C++ Standard Library](../standard-library/cpp-standard-library-reference.md)

docs/cpp/references-cpp.md

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,33 @@ description: "Learn more about: References (C++)"
33
title: "References (C++)"
44
ms.date: "11/04/2016"
55
helpviewer_keywords: ["objects [C++], referencing", "references [C++]", "references, to pointers", "declarations, references", "references, declaring", "referencing objects, declarator syntax"]
6-
ms.assetid: 68156f7f-97a0-4b66-b26d-b25ade5e3bd8
76
---
87
# References (C++)
98

10-
A reference, like a pointer, stores the address of an object that is located elsewhere in memory. Unlike a pointer, a reference after it is initialized cannot be made to refer to a different object or set to null. There are two kinds of references: lvalue references which refer to a named variable and rvalue references which refer to a [temporary object](../cpp/temporary-objects.md). The & operator signifies an lvalue reference and the && operator signifies either an rvalue reference, or a universal reference (either rvalue or lvalue) depending on the context.
9+
A reference, like a pointer, stores the address of an object that is located elsewhere in memory. Unlike a pointer, a reference after it's initialized can't be made to refer to a different object or set to null. There are two kinds of references: *lvalue* references, which refer to a named variable and *rvalue* references, which refer to a [temporary object](../cpp/temporary-objects.md). The `&` operator signifies an lvalue reference and the `&&` operator signifies either an rvalue reference, or a universal reference (either rvalue or lvalue) depending on the context.
1110

1211
References may be declared using the following syntax:
1312

14-
> \[*storage-class-specifiers*] \[*cv-qualifiers*] *type-specifiers* \[*ms-modifier*] *declarator* \[**=** *expression*]**;**
13+
> \[*storage-class-specifiers*] \[*cv-qualifiers*] *type-specifiers* \[*ms-modifier*] *declarator* \[**`=`** *expression*]**`;`**
1514
1615
Any valid declarator specifying a reference may be used. Unless the reference is a reference to function or array type, the following simplified syntax applies:
1716

18-
> \[*storage-class-specifiers*] \[*cv-qualifiers*] *type-specifiers* \[**&** or **&&**] \[*cv-qualifiers*] *identifier* \[**=** *expression*]**;**
17+
> \[*storage-class-specifiers*] \[*cv-qualifiers*] *type-specifiers* \[**`&`** or **`&&`**] \[*cv-qualifiers*] *identifier* \[**`=`** *expression*]**`;`**
1918
2019
References are declared using the following sequence:
2120

2221
1. The declaration specifiers:
2322

2423
- An optional storage class specifier.
25-
2624
- Optional **`const`** and/or **`volatile`** qualifiers.
27-
2825
- The type specifier: the name of a type.
2926

3027
1. The declarator:
3128

3229
- An optional Microsoft-specific modifier. For more information, see [Microsoft-Specific Modifiers](../cpp/microsoft-specific-modifiers.md).
3330

34-
- The **&** operator or **&&** operator.
35-
31+
- The **`&`** operator or **`&&`** operator.
3632
- Optional **`const`** and/or **`volatile`** qualifers.
37-
3833
- The identifier.
3934

4035
1. An optional initializer.
@@ -48,7 +43,7 @@ int &i;
4843
int &i, &j;
4944
```
5045

51-
References, pointers and objects may be declared together:
46+
References, pointers, and objects may be declared together:
5247

5348
```cpp
5449
int &ref, *ptr, k;

0 commit comments

Comments
 (0)