Commit 0c371225 authored by GILLES Sebastien's avatar GILLES Sebastien
Browse files

Error handling notebook: add more content, and clean-up.

parent 6b3a2e24
......@@ -4,31 +4,30 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"# [Getting started in C++](/) - [Useful concepts and STL](/notebooks/5-UsefulConceptsAndSTL/0-main.ipynb)"
"# [Getting started in C++](/) - [Useful concepts and STL](./0-main.ipynb)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* [Error handling](/notebooks/5-UsefulConceptsAndSTL/1-ErrorHandling.ipynb)\n",
" * [TP 14](/notebooks/5-UsefulConceptsAndSTL/1b-TP.ipynb)\n",
"* [RAII idiom](/notebooks/5-UsefulConceptsAndSTL/2-RAII.ipynb)\n",
"* [Containers](/notebooks/5-UsefulConceptsAndSTL/3-Containers.ipynb)\n",
" * [TP 15](/notebooks/5-UsefulConceptsAndSTL/3b-TP.ipynb)\n",
"* [Associative containers](/notebooks/5-UsefulConceptsAndSTL/4-AssociativeContainers.ipynb)\n",
"* [Move semantics](/notebooks/5-UsefulConceptsAndSTL/5-MoveSemantics.ipynb)\n",
"* [Smart pointers](/notebooks/5-UsefulConceptsAndSTL/6-SmartPointers.ipynb)\n",
" * [TP 16](/notebooks/5-UsefulConceptsAndSTL/6b-TP.ipynb)\n",
"* [Algorithms](/notebooks/5-UsefulConceptsAndSTL/7-Algorithms.ipynb)\n"
"* [Error handling](./1-ErrorHandling.ipynb)\n",
" * [TP 14](./1b-TP.ipynb)\n",
"* [RAII idiom](./2-RAII.ipynb)\n",
"* [Containers](./3-Containers.ipynb)\n",
" * [TP 15](./3b-TP.ipynb)\n",
"* [Associative containers](./4-AssociativeContainers.ipynb)\n",
"* [Move semantics](./5-MoveSemantics.ipynb)\n",
"* [Smart pointers](./6-SmartPointers.ipynb)\n",
" * [TP 16](./6b-TP.ipynb)\n",
"* [Algorithms](./7-Algorithms.ipynb)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"© _CNRS 2016_ - _Inria 2018-2019_ \n",
"© _CNRS 2016_ - _Inria 2018-2020_ \n",
"_This notebook is an adaptation of a lecture prepared by David Chamont (CNRS) under the terms of the licence [Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)](http://creativecommons.org/licenses/by-nc-sa/4.0/)_ \n",
"_The present version has been written by Sébastien Gilles and Vincent Rouvreau (Inria)_"
]
......@@ -38,14 +37,14 @@
"kernelspec": {
"display_name": "C++17",
"language": "C++17",
"name": "xeus-cling-cpp17"
"name": "xcpp17"
},
"language_info": {
"codemirror_mode": "text/x-c++src",
"file_extension": ".cpp",
"mimetype": "text/x-c++src",
"name": "c++",
"version": "-std=c++17"
"version": "17"
},
"latex_envs": {
"LaTeX_envs_menu_present": true,
......
......@@ -4,7 +4,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"# [Getting started in C++](/) - [Useful concepts and STL](/notebooks/5-UsefulConceptsAndSTL/0-main.ipynb) - [Error handling](/notebooks/5-UsefulConceptsAndSTL/1-ErrorHandling.ipynb)"
"# [Getting started in C++](/) - [Useful concepts and STL](./0-main.ipynb) - [Error handling](./1-ErrorHandling.ipynb)"
]
},
{
......@@ -14,7 +14,7 @@
},
"source": [
"<h1>Table of contents<span class=\"tocSkip\"></span></h1>\n",
"<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#Introduction\" data-toc-modified-id=\"Introduction-1\">Introduction</a></span></li><li><span><a href=\"#Compiler-warnings-and-errors\" data-toc-modified-id=\"Compiler-warnings-and-errors-2\">Compiler warnings and errors</a></span></li><li><span><a href=\"#Assert\" data-toc-modified-id=\"Assert-3\">Assert</a></span></li><li><span><a href=\"#Exceptions\" data-toc-modified-id=\"Exceptions-4\">Exceptions</a></span><ul class=\"toc-item\"><li><span><a href=\"#throw\" data-toc-modified-id=\"throw-4.1\"><code>throw</code></a></span></li><li><span><a href=\"#try/catch\" data-toc-modified-id=\"try/catch-4.2\"><code>try</code>/<code>catch</code></a></span></li><li><span><a href=\"#Good-practice:-use-as-much-as-possible-exceptions-that-derive-from-std::exception\" data-toc-modified-id=\"Good-practice:-use-as-much-as-possible-exceptions-that-derive-from-std::exception-4.3\">Good practice: use as much as possible exceptions that derive from <code>std::exception</code></a></span></li><li><span><a href=\"#Good-practice:-be-wary-of-a-forest-of-exception-classes\" data-toc-modified-id=\"Good-practice:-be-wary-of-a-forest-of-exception-classes-4.4\">Good practice: be wary of a forest of exception classes</a></span></li><li><span><a href=\"#noexcept\" data-toc-modified-id=\"noexcept-4.5\"><code>noexcept</code></a></span></li><li><span><a href=\"#Good-practice:-never-throw-an-exception-from-a-destructor\" data-toc-modified-id=\"Good-practice:-never-throw-an-exception-from-a-destructor-4.6\">Good practice: never throw an exception from a destructor</a></span></li><li><span><a href=\"#The-exception-class-I-use\" data-toc-modified-id=\"The-exception-class-I-use-4.7\">The exception class I use</a></span></li></ul></li><li><span><a href=\"#Error-codes\" data-toc-modified-id=\"Error-codes-5\">Error codes</a></span></li></ul></div>"
"<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#Introduction\" data-toc-modified-id=\"Introduction-1\">Introduction</a></span></li><li><span><a href=\"#Compiler-warnings-and-errors\" data-toc-modified-id=\"Compiler-warnings-and-errors-2\">Compiler warnings and errors</a></span></li><li><span><a href=\"#Assert\" data-toc-modified-id=\"Assert-3\">Assert</a></span></li><li><span><a href=\"#Exceptions\" data-toc-modified-id=\"Exceptions-4\">Exceptions</a></span><ul class=\"toc-item\"><li><span><a href=\"#throw\" data-toc-modified-id=\"throw-4.1\"><code>throw</code></a></span></li><li><span><a href=\"#try/catch\" data-toc-modified-id=\"try/catch-4.2\"><code>try</code>/<code>catch</code></a></span></li><li><span><a href=\"#Re-throw\" data-toc-modified-id=\"Re-throw-4.3\">Re-throw</a></span></li><li><span><a href=\"#Good-practice:-use-as-much-as-possible-exceptions-that-derive-from-std::exception\" data-toc-modified-id=\"Good-practice:-use-as-much-as-possible-exceptions-that-derive-from-std::exception-4.4\">Good practice: use as much as possible exceptions that derive from <code>std::exception</code></a></span></li><li><span><a href=\"#Good-practice:-be-wary-of-a-forest-of-exception-classes\" data-toc-modified-id=\"Good-practice:-be-wary-of-a-forest-of-exception-classes-4.5\">Good practice: be wary of a forest of exception classes</a></span></li><li><span><a href=\"#noexcept\" data-toc-modified-id=\"noexcept-4.6\"><code>noexcept</code></a></span></li><li><span><a href=\"#Good-practice:-never-throw-an-exception-from-a-destructor\" data-toc-modified-id=\"Good-practice:-never-throw-an-exception-from-a-destructor-4.7\">Good practice: never throw an exception from a destructor</a></span></li><li><span><a href=\"#The-exception-class-I-use\" data-toc-modified-id=\"The-exception-class-I-use-4.8\">The exception class I use</a></span></li></ul></li><li><span><a href=\"#Error-codes\" data-toc-modified-id=\"Error-codes-5\">Error codes</a></span><ul class=\"toc-item\"><li><span><a href=\"#nodiscard\" data-toc-modified-id=\"nodiscard-5.1\">nodiscard</a></span></li></ul></li></ul></div>"
]
},
{
......@@ -29,10 +29,10 @@
"\n",
"The first way to find out possible errors are during compilation time: you may ensure your code is correct by making its compilation fails if not. There are many ways to do so, even more so if templates are involved; here are few of them we have already seen:\n",
"\n",
"* `static_assert` we saw in [template introduction](/notebooks/4-Templates/1-Intro.ipynb#static_assert)\n",
"* `static_assert` we saw in [template introduction](../4-Templates/1-Intro.ipynb#static_assert)\n",
"* Duck typing failure: if a template argument used somewhere doesn't comply with the expected API.\n",
"* Locality of reference: use heavily blocks so that a variable is freed as soon as possible. This way, you will avoid mistakes of using a variable that is in fact no longer up-to-date.\n",
"* Strive to make your code without any compiler warning: if there are even as less as 10 warnings, you might not see an eleventh that might sneak its way at some point. Activate as many warnings as possible for your compiler, and deactivate those unwanted with care (see [this notebook](/notebooks/6-InRealEnvironment/4-ThirdParty.ipynb) to see how to manage third party warnings.).\n",
"* Strive to make your code without any compiler warning: if there are even as less as 10 warnings, you might not see an eleventh that might sneak its way at some point. Activate as many type of warnings as possible for your compiler, and deactivate those unwanted with care (see [this notebook](../6-InRealEnvironment/4-ThirdParty.ipynb) to see how to manage third party warnings.).\n",
"\n",
"## Assert\n",
"\n",
......@@ -67,9 +67,9 @@
"source": [
"(here in Xeus-cling it breaks the kernel...)\n",
"\n",
"The perk of `assert` is that it checks the condition is `true` *only in debug mode*!\n",
"The perk of `assert` is that it checks the condition is `true` *only in debug mode*! \n",
"\n",
"So you may get extensive tests in debug mode that are ignored once your code has been thoroughly checked and is ready for production use.\n",
"So you may get extensive tests in debug mode that are ignored once your code has been thoroughly checked and is ready for production use (_debug_ and _release_ mode will be explained in a [later notebook](../6-InRealEnvironment/3-Compilers.ipynb#Debug-and-release-flags)).\n",
"\n",
"The example above is a very useful use: before dereferencing a pointer check it is not `nullptr` (hence the good practice to always initialize a pointer to `nullptr`...)\n",
"\n",
......@@ -203,7 +203,7 @@
" { \n",
" FunctionThatExpectsSingleDigitNumber(15);\n",
" }\n",
" catch(float n) // doesn't work!\n",
" catch(float n) // doesn't catch your `int` exception!\n",
" {\n",
" std::cout << \"Float case: \" << n << \" was provided and is not an integer\" << std::endl;\n",
" }\n",
......@@ -214,6 +214,58 @@
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Re-throw\n",
"\n",
"Once an exception has been caught by a `catch` block, it is considered to be handled; the code will therefore go on to what is immediately after the block. If you want to throw the exception again (for instance afterloggin a message) you may just type `throw`:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"// No re-throw\n",
"{\n",
" try\n",
" { \n",
" FunctionThatExpectsSingleDigitNumber(15);\n",
" }\n",
" catch(int n)\n",
" {\n",
" std::cout << \"Int case: \" << n << \" not a single digit number\" << std::endl;\n",
" }\n",
" \n",
" std::cout << \"After catch\" << std::endl;\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"// Rethrow\n",
"{\n",
" try\n",
" { \n",
" FunctionThatExpectsSingleDigitNumber(15);\n",
" }\n",
" catch(int n)\n",
" {\n",
" std::cout << \"Int case: \" << n << \" not a single digit number\" << std::endl;\n",
" throw; // `throw n` would have been correct as well but is not necessary\n",
" }\n",
" \n",
" std::cout << \"After catch\" << std::endl;\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
......@@ -377,17 +429,19 @@
"source": [
"### Good practice: never throw an exception from a destructor\n",
"\n",
"The explanation is quite subtle and explained in detail in item 8 of \\cite{Meyers2005}; however just know you should never throw an exception there. If you need to deal with it, use something else (`std::abort` for instance).\n",
"The explanation is quite subtle and explained in detail in item 8 of \\cite{Meyers2005}; however just know you should never throw an exception there. If you need to deal with an error there, use something else (`std::abort` for instance).\n",
"\n",
"\n",
"### The exception class I use\n",
"\n",
"I provide in [appendix](/notebooks/7-Appendix/HomemadeException.ipynb) my own exception class (which of course derives from `std::exception`) which provides additionally:\n",
"I (Sébastien) provide in [appendix](/notebooks/7-Appendix/HomemadeException.ipynb) my own exception class (which of course derives from `std::exception`) which provides additionally:\n",
"\n",
"* A constructor with a string, to avoid defining a verbosy dedicated exception class for each case.\n",
"* Better management of the string display, with an underlying `std::string` object.\n",
"* Information about the location from where the exception was thrown.\n",
"\n",
"Vincent uses up the STL exceptions described in [previous section](#Good-practice:-be-wary-of-a-forest-of-exception-classes).\n",
"\n",
"## Error codes\n",
"\n",
"A quick word about C-style error management which you might find in use in some libraries: **error codes**.\n",
......@@ -437,7 +491,7 @@
"I don't like these error codes much, because:\n",
"\n",
"* The result can't be naturally given in return value and must be provided in argument.\n",
"* You have to bookkeep the possible error codes somewhere, and a user must know this somewhere to go consult them if something happens.\n",
"* You have to bookkeep the possible error codes somewhere, and a user must know this somewhere to go consult them if something happens (usually a header file: see for instance one for [PETSc library](https://www.mcs.anl.gov/petsc/petsc-master/include/petscerror.h.html)).\n",
"* In the libraries that use them, more often than not some are not self descriptive and you have to figure out what the hell the issue is.\n",
"* And more importantly, this relies on the end-user thinking to check the error value:"
]
......@@ -462,9 +516,51 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"### nodiscard\n",
"\n",
"The latter point may however be mitigated since C++17 with the attribute [nodiscard](https://en.cppreference.com/w/cpp/language/attributes/nodiscard), which helps your compiler figure out the return value should have been checked."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"\n",
"template<class T>\n",
"[[nodiscard]] int AbsoluteValueNoDiscard(T value, T& result)\n",
"{\n",
" if constexpr (!std::is_arithmetic<T>())\n",
" return INVALID_TYPE;\n",
" else\n",
" {\n",
" if (value < 0)\n",
" result = -value;\n",
" else\n",
" result = value;\n",
"\n",
" return EXIT_SUCCESS;\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#include <string>\n",
"\n",
"{\n",
" std::string hello(\"Hello world\");\n",
" std::string absolute_value = \"\";\n",
" \n",
" AbsoluteValueNoDiscard(hello, absolute_value); // Now there is a warning! But only available after C++ 17...\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
......@@ -484,7 +580,7 @@
"metadata": {},
"source": [
"\n",
"© _CNRS 2016_ - _Inria 2018-2019_ \n",
"© _CNRS 2016_ - _Inria 2018-2020_ \n",
"_This notebook is an adaptation of a lecture prepared by David Chamont (CNRS) under the terms of the licence [Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)](http://creativecommons.org/licenses/by-nc-sa/4.0/)_ \n",
"_The present version has been written by Sébastien Gilles and Vincent Rouvreau (Inria)_"
]
......@@ -494,14 +590,14 @@
"kernelspec": {
"display_name": "C++17",
"language": "C++17",
"name": "xeus-cling-cpp17"
"name": "xcpp17"
},
"language_info": {
"codemirror_mode": "text/x-c++src",
"file_extension": ".cpp",
"mimetype": "text/x-c++src",
"name": "c++",
"version": "-std=c++17"
"version": "17"
},
"latex_envs": {
"LaTeX_envs_menu_present": true,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment