From 02b0896f45075a32d2bfa5e0a9ec3d1dfaff4085 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Mon, 15 May 2023 09:17:57 -0400 Subject: [PATCH 001/156] Fix a few spaces. --- talk/introduction/goals.tex | 2 +- talk/introduction/history.tex | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/talk/introduction/goals.tex b/talk/introduction/goals.tex index b9e461ea..1991e0d7 100644 --- a/talk/introduction/goals.tex +++ b/talk/introduction/goals.tex @@ -1,7 +1,7 @@ \subsection[Use]{Why we use it?} \begin{frame} - \frametitle{Why is \cpp our language of choice?} + \frametitle{Why is \cpp{} our language of choice?} \begin{block}{Adapted to large projects} \begin{itemize} \item statically and strongly typed diff --git a/talk/introduction/history.tex b/talk/introduction/history.tex index 3b7b92fc..1081ccb6 100644 --- a/talk/introduction/history.tex +++ b/talk/introduction/history.tex @@ -1,7 +1,7 @@ \subsection[Hist]{History} \begin{frame} - \frametitle{C/\cpp origins} + \frametitle{C/\cpp{} origins} \begin{minipage}{0.4\linewidth} \tikzstyle{old}=[ellipse,draw=black,fill=orange!30,thick,inner sep=2pt] \tikzstyle{new}=[rectangle,draw=black,fill=green!50,thick,inner sep=2pt] @@ -100,8 +100,8 @@ \begin{multicols}{2} \begin{itemize} \item Use a compatible compiler - \item add -std=c++xx to compilation flags - \item e.g. -std=c++17 + \item add \texttt{-std=c++xx} to compilation flags + \item e.g.\ \texttt{-std=c++17} \end{itemize} \vfill \columnbreak From dca8fbcd181278ff014db686da1d3712df5ce62b Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Mon, 15 May 2023 11:51:35 -0400 Subject: [PATCH 002/156] Fix a comment about [[fallthrough]]. By trying a few compilers, it's apparent that warnings are only emitted when a case is not empty. This seems to be accepted without warnings: case 2: case 3: statement(); --- talk/basicconcepts/control.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/talk/basicconcepts/control.tex b/talk/basicconcepts/control.tex index 8786a37f..904e15ce 100644 --- a/talk/basicconcepts/control.tex +++ b/talk/basicconcepts/control.tex @@ -134,7 +134,7 @@ switch (c) { case 'a': f(); // Warning emitted - case 'b': // Warning emitted + case 'b': // Warning probably suppressed case 'c': g(); [[fallthrough]]; // Warning suppressed From f257d63de8194c641a5eac522734587a7a5f75da Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Mon, 15 May 2023 11:53:39 -0400 Subject: [PATCH 003/156] Add an example for calling functions and binding to returned values. We were missing an example for const ref to temporaries. As it happens, the next chapter starts with functions and return types, so it might be beneficial to show it there. --- talk/basicconcepts/functions.tex | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/talk/basicconcepts/functions.tex b/talk/basicconcepts/functions.tex index a64faf6e..24fa7461 100644 --- a/talk/basicconcepts/functions.tex +++ b/talk/basicconcepts/functions.tex @@ -28,6 +28,16 @@ } \end{cppcode*} \end{multicols} + + \pause + + \begin{exampleblock}{Functions and references to returned values} + \begin{cppcode} + int result = square(2); + int & temp = square(2); // Not allowed + int const & temp2 = square(2); // OK + \end{cppcode} + \end{exampleblock} \end{frame} \begin{frame}[fragile] From 327252eb87ebc593f4438caea01dd30de8aee934 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Mon, 15 May 2023 15:03:16 -0400 Subject: [PATCH 004/156] Clarify two things in code/README --- code/README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/code/README.md b/code/README.md index 19be3d32..b60706e4 100644 --- a/code/README.md +++ b/code/README.md @@ -33,12 +33,14 @@ Recommended setup - `valgrind`, `kcachegrind`, `cppcheck`, `clang-format` and `clang-tidy` for corresponding exercises - `g++` or `clang++` as C++ compiler for sanitizer exercises -### C++ and python specific needs +### More setup for the advanced course + +#### C++ and python specific needs - `python3`, `libpython3-dev` - `ctypes`, `matplotlib`, `numpy` python packages -### A word on timing +#### A word on timing - several exercises ask you to "time" things - here it's always sufficient to use the `time` command line: @@ -54,6 +56,7 @@ Recommended setup How to test your setup ---------------------- - **Please run [`check_setup.sh`](check_setup.sh) to check your setup on Linux / Mac.** + The optional tools are not required for the essentials course. - go to [`code/hello`](hello) - follow the `README.md` From 7a2c0a85bf3512aa646580f6a08ce73819a9a49c Mon Sep 17 00:00:00 2001 From: Bernhard Manfred Gruber Date: Wed, 17 May 2023 16:31:00 +0200 Subject: [PATCH 005/156] Make function exercise print only 5 chars Fix #462 --- code/functions/functions.cpp | 7 ++++--- code/functions/solution/functions.sol.cpp | 17 ++++++++++++----- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/code/functions/functions.cpp b/code/functions/functions.cpp index eac526db..c2089bef 100644 --- a/code/functions/functions.cpp +++ b/code/functions/functions.cpp @@ -12,6 +12,7 @@ * argument.name[0] = 'a'; * to your print function. * Try both with and without const attributes in your print function's signature. + * 5. Bonus: Can you fix "printFiveCharacters" to actually only print the first five characters and not the entire string? */ #include "Structs.h" // The data structs we will work with @@ -19,14 +20,14 @@ #include // For printing void printFiveCharacters(FastToCopy argument) { - std::cout << argument.name << "\n"; + std::cout << argument.name << '\n'; } int main() { - FastToCopy fast = {"abcdef"}; + FastToCopy fast = {"abcdefghijkl"}; printFiveCharacters(fast); - SlowToCopy slow = {"ghijkl"}; + SlowToCopy slow = {"ABCDEFGHIJKL"}; // print it here return 0; diff --git a/code/functions/solution/functions.sol.cpp b/code/functions/solution/functions.sol.cpp index 639cd1e3..50c39f66 100644 --- a/code/functions/solution/functions.sol.cpp +++ b/code/functions/solution/functions.sol.cpp @@ -19,25 +19,32 @@ #include // For printing void printFiveCharacters(FastToCopy argument) { - std::cout << argument.name << "\n"; + for (int i = 0; i < 5; i++) + std::cout << argument.name[i]; + std::cout << '\n'; + + // alternative 1: std::cout << argument.name.substr(0, 5) << '\n'; + // alternative 2: std::cout << std::string_view{argument.name.data(), 5} << '\n'; + // alternative C: std::printf("%.5s\n", argument.name.c_str()); + // alternative C++23: std::print("{:.5}\n", argument); } void printFiveCharacters(const SlowToCopy & argument) { //argument.data[0] = '\n' ; // EXPECTED COMPILATION ERROR - std::cout << argument.name << "\n"; + std::cout << argument.name << '\n'; } void printFiveCharactersWithCopy(SlowToCopy argument) { - std::cout << argument.name << "\n"; + std::cout << argument.name << '\n'; // We can actually modify the argument if we want, since it's a copy: argument.name[0] = 'a'; } int main() { - FastToCopy fast = {"abcdef"}; + FastToCopy fast = {"abcdefghijkl"}; printFiveCharacters(fast); - SlowToCopy slow = {"ghijkl"}; + SlowToCopy slow = {"ABCDEFGHIJKL"}; printFiveCharacters(slow); std::cout << "Now printing with copy:\n"; From 90770c82907e891e54bd08296851f38a183d6c13 Mon Sep 17 00:00:00 2001 From: Bernhard Manfred Gruber Date: Tue, 16 May 2023 23:59:27 -0400 Subject: [PATCH 006/156] Small improvements of core modern C++ chapter --- talk/morelanguage/constness.tex | 4 ++-- talk/morelanguage/stl.tex | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/talk/morelanguage/constness.tex b/talk/morelanguage/constness.tex index 4d51628e..000003da 100644 --- a/talk/morelanguage/constness.tex +++ b/talk/morelanguage/constness.tex @@ -16,7 +16,7 @@ int const i = 6; const int i = 6; // equivalent - // error : i is constant + // error: i is constant i = 5; auto const j = i; // works with auto @@ -77,7 +77,7 @@ \begin{block}{Constness is part of the type} \begin{itemize} \item \cppinline{T const} and \cppinline{T} are different types - \item however: \cppinline{T} is automatically cast to \cppinline{T const} when needed + \item but: \cppinline{T} is automatically converted to \cppinline{T const} when needed \end{itemize} \end{block} \begin{cppcode} diff --git a/talk/morelanguage/stl.tex b/talk/morelanguage/stl.tex index d3163e00..c6d44e32 100644 --- a/talk/morelanguage/stl.tex +++ b/talk/morelanguage/stl.tex @@ -39,7 +39,7 @@ out.begin(), // start result std::negate{}); // function obj std::copy(out.begin(), out.end(), // -5 -3 -4 - std::ostream_iterator{std::cout, " "}); + std::ostream_iterator{std::cout, " "}); \end{cppcode*} \end{exampleblockGB} \end{frame} From d1e0ac95dde7cf9868046604fe9a8ebc72f949ea Mon Sep 17 00:00:00 2001 From: Bernhard Manfred Gruber Date: Mon, 15 May 2023 21:40:15 -0400 Subject: [PATCH 007/156] Minor improvements after JLab course --- talk/C++Course.tex | 9 +++++++-- talk/basicconcepts/functions.tex | 8 +++++--- talk/basicconcepts/operators.tex | 1 + talk/introduction/history.tex | 4 ++-- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/talk/C++Course.tex b/talk/C++Course.tex index 20442ca2..45f8bcd1 100644 --- a/talk/C++Course.tex +++ b/talk/C++Course.tex @@ -56,8 +56,13 @@ \end{block} \begin{block}{Where to find latest version ?} \begin{itemize} - \item full sources at {\scriptsize \url{https://github.com/hsf-training/cpluspluscourse}} - \item latest pdf under {\scriptsize \href{https://github.com/hsf-training/cpluspluscourse/raw/download/talk/C++Course\_full.pdf}{raw/download/talk/C++Course\_full.pdf}} + \item full sources at \href{https://github.com/hsf-training/cpluspluscourse}{github.com/hsf-training/cpluspluscourse} + \item latest pdf on + \ifbasic + \href{https://github.com/hsf-training/cpluspluscourse/raw/download/talk/C++Course\_essentials.pdf}{GitHub} + \else + \href{https://github.com/hsf-training/cpluspluscourse/raw/download/talk/C++Course\_full.pdf}{GitHub} + \fi \end{itemize} \end{block} \end{frame} diff --git a/talk/basicconcepts/functions.tex b/talk/basicconcepts/functions.tex index 24fa7461..7c12b750 100644 --- a/talk/basicconcepts/functions.tex +++ b/talk/basicconcepts/functions.tex @@ -215,10 +215,12 @@ \begin{block}{Overloading} \begin{itemize} \item We can have multiple functions with the same name - \item They must have different parameter lists - \item A different return type alone is not allowed + \begin{itemize} + \item Must have different parameter lists + \item A different return type alone is not allowed + \item Form a so-called ``overload set'' + \end{itemize} \item Default arguments can cause ambiguities - \item All functions with the same name form an ``overload set'' \end{itemize} \end{block} \begin{exampleblock}{} diff --git a/talk/basicconcepts/operators.tex b/talk/basicconcepts/operators.tex index 1ea2f8af..e9834e83 100644 --- a/talk/basicconcepts/operators.tex +++ b/talk/basicconcepts/operators.tex @@ -56,6 +56,7 @@ bool d = (4 <= 4); // true bool e = (4 > 4); // false bool f = (4 >= 4); // true + auto g = (5 <=> 5); // C++20 (later) \end{cppcode*} \end{block} \pause diff --git a/talk/introduction/history.tex b/talk/introduction/history.tex index 1081ccb6..b0fd56d1 100644 --- a/talk/introduction/history.tex +++ b/talk/introduction/history.tex @@ -85,11 +85,11 @@ \begin{frame} \frametitle{\cpp11, \cpp14, \cpp17, \cpp20, \cpp23, \cpp26...} - \begin{block}{status} + \begin{block}{Status} \begin{itemize} \item A new \cpp specification every 3 years \begin{itemize} - \item \cpp23 complete since 11th of Feb. 2023, awaiting ISO ballot + \item \cpp23 complete since 11\textsuperscript{th} of Feb. 2023, awaiting ISO ballot \item work on \cpp26 has begun \end{itemize} \item Bringing each time a lot of goodies From a3ae28fe7ee7edfdd80290f38030a8daa4565623 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Wed, 17 May 2023 11:30:13 -0400 Subject: [PATCH 008/156] Remove stray period --- talk/morelanguage/stl.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/talk/morelanguage/stl.tex b/talk/morelanguage/stl.tex index c6d44e32..c806d11b 100644 --- a/talk/morelanguage/stl.tex +++ b/talk/morelanguage/stl.tex @@ -164,7 +164,7 @@ template<> struct std::hash { std::size_t operator()(MyClass const& c) { std::hash h; - return h(c.a) ^ h(c.b.); // xor to combine hashes + return h(c.a) ^ h(c.b); // xor to combine hashes } }; \end{cppcode*} From 9015d25e6e17ba1b8883465584db675b4a2f4c24 Mon Sep 17 00:00:00 2001 From: Bernhard Manfred Gruber Date: Tue, 16 May 2023 15:48:31 -0400 Subject: [PATCH 009/156] Rename Polygon to RegularPolygon --- code/polymorphism/Polygons.cpp | 8 ++++---- code/polymorphism/Polygons.hpp | 8 ++++---- code/polymorphism/solution/trypoly.sol.cpp | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/code/polymorphism/Polygons.cpp b/code/polymorphism/Polygons.cpp index e285ca18..89ec73ef 100644 --- a/code/polymorphism/Polygons.cpp +++ b/code/polymorphism/Polygons.cpp @@ -2,16 +2,16 @@ #include #include -Polygon::Polygon(int n, float radius) : m_nbSides(n), m_radius(radius) {}; +RegularPolygon::RegularPolygon(int n, float radius) : m_nbSides(n), m_radius(radius) {}; -float Polygon::computePerimeter() const { +float RegularPolygon::computePerimeter() const { std::cout << "Polygon::computePerimeter is being called\n"; return 2*m_nbSides*std::sin(static_cast(M_PI)/m_nbSides)*m_radius; } -Pentagon::Pentagon(float radius) : Polygon(5, radius) {} +Pentagon::Pentagon(float radius) : RegularPolygon(5, radius) {} -Hexagon::Hexagon(float radius) : Polygon(6, radius) {} +Hexagon::Hexagon(float radius) : RegularPolygon(6, radius) {} float Hexagon::computePerimeter() const { std::cout << "Hexagon::computePerimeter is being called\n"; diff --git a/code/polymorphism/Polygons.hpp b/code/polymorphism/Polygons.hpp index 9c164ba0..a7715f81 100644 --- a/code/polymorphism/Polygons.hpp +++ b/code/polymorphism/Polygons.hpp @@ -1,20 +1,20 @@ #pragma once -class Polygon { +class RegularPolygon { public: - Polygon(int n, float radius); + RegularPolygon(int n, float radius); float computePerimeter() const; protected: int m_nbSides; float m_radius; }; -class Pentagon : public Polygon { +class Pentagon : public RegularPolygon { public: Pentagon(float radius); }; -class Hexagon : public Polygon { +class Hexagon : public RegularPolygon { public: Hexagon(float radius); // 6*radius is easier than generic case diff --git a/code/polymorphism/solution/trypoly.sol.cpp b/code/polymorphism/solution/trypoly.sol.cpp index e598bee2..50325d41 100644 --- a/code/polymorphism/solution/trypoly.sol.cpp +++ b/code/polymorphism/solution/trypoly.sol.cpp @@ -12,7 +12,7 @@ int main() { // create a Hexagon, call the perimeter method through a reference to Polygon Hexagon hexa2{1.0}; - Polygon &poly = hexa2; + RegularPolygon &poly = hexa2; std::cout << "Hexa : perimeter = " << hexa2.computePerimeter() << '\n' << "Hexa as Poly : perimeter = " << poly.computePerimeter() << '\n'; From 57ce506bde8eaac22badf40260ce9b3e6b836097 Mon Sep 17 00:00:00 2001 From: Bernhard Manfred Gruber Date: Tue, 16 May 2023 15:48:49 -0400 Subject: [PATCH 010/156] Add some space to math expression --- code/polymorphism/Polygons.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/polymorphism/Polygons.cpp b/code/polymorphism/Polygons.cpp index 89ec73ef..a94383a0 100644 --- a/code/polymorphism/Polygons.cpp +++ b/code/polymorphism/Polygons.cpp @@ -6,7 +6,7 @@ RegularPolygon::RegularPolygon(int n, float radius) : m_nbSides(n), m_radius(rad float RegularPolygon::computePerimeter() const { std::cout << "Polygon::computePerimeter is being called\n"; - return 2*m_nbSides*std::sin(static_cast(M_PI)/m_nbSides)*m_radius; + return 2 * m_nbSides * std::sin(static_cast(M_PI) / m_nbSides) * m_radius; } Pentagon::Pentagon(float radius) : RegularPolygon(5, radius) {} From 36ffe65d2fb365153866cc0621ee8bc8cd3083f7 Mon Sep 17 00:00:00 2001 From: Bernhard Manfred Gruber Date: Tue, 16 May 2023 14:13:01 -0400 Subject: [PATCH 011/156] Simplify debug and valgrind exercise By avoiding an int**. Clarify intention of debug/valgrind exercise Fix out of bounds access --- code/debug/randomize.cpp | 16 ++++++++-------- code/debug/solution/randomize.sol.cpp | 16 ++++++++-------- code/valgrind/randomize.cpp | 16 ++++++++-------- code/valgrind/solution/randomize.sol.cpp | 16 ++++++++-------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/code/debug/randomize.cpp b/code/debug/randomize.cpp index 8832a81b..966f6413 100644 --- a/code/debug/randomize.cpp +++ b/code/debug/randomize.cpp @@ -13,7 +13,7 @@ void swap(int *a, int*b) { void randomize(int* v, unsigned int len) { std::default_random_engine e; - std::uniform_int_distribution d{0u, len}; + std::uniform_int_distribution d{0u, len - 1}; // we randomize via len random inversions for (unsigned int i = 0; i < len; i++) { int a = d(e); @@ -22,23 +22,23 @@ void randomize(int* v, unsigned int len) { } } -void createAndFillVector(int** v, unsigned int len) { - *v = new int[LEN]; - for (unsigned int i = 0; i < len; i++) (*v)[i] = i*STEP; +void createAndFillVector(int*& v, unsigned int len) { + v = new int[LEN]; + for (unsigned int i = 0; i < len; i++) v[i] = i*STEP; } int main() { int *v = nullptr; - // create and randomize vector + // create and randomize vector of LEN+1 numbers randomize(v, LEN+1); - createAndFillVector(&v, LEN+1); + createAndFillVector(v, LEN+1); - // compute diffs + // compute LEN diffs int *diffs = new int[LEN]; for (unsigned int i = 0; i < LEN; i++) diffs[i] = v[i+1] - v[i]; - // compute standard deviation of it + // compute mean and standard deviation of diffs float sum = 0; float sumsq = 0; for (unsigned int i = 0; i < LEN; i ++) { diff --git a/code/debug/solution/randomize.sol.cpp b/code/debug/solution/randomize.sol.cpp index 77d89f1d..fdd32476 100644 --- a/code/debug/solution/randomize.sol.cpp +++ b/code/debug/solution/randomize.sol.cpp @@ -13,7 +13,7 @@ void swap(int *a, int*b) { void randomize(int* v, unsigned int len) { std::default_random_engine e; - std::uniform_int_distribution d{0u, len}; + std::uniform_int_distribution d{0u, len - 1}; // we randomize via len random inversions for (unsigned int i = 0; i < len; i++) { int a = d(e); @@ -22,23 +22,23 @@ void randomize(int* v, unsigned int len) { } } -void createAndFillVector(int** v, unsigned int len) { - *v = new int[len]; - for (unsigned int i = 0; i < len; i++) (*v)[i] = i*STEP; +void createAndFillVector(int*& v, unsigned int len) { + v = new int[len]; + for (unsigned int i = 0; i < len; i++) v[i] = i*STEP; } int main() { int *v = nullptr; - // create and randomize vector - createAndFillVector(&v, LEN+1); + // create and randomize vector of LEN+1 numbers + createAndFillVector(v, LEN+1); randomize(v, LEN+1); - // compute diffs + // compute LEN diffs int *diffs = new int[LEN]; for (unsigned int i = 0; i < LEN; i++) diffs[i] = v[i+1] - v[i]; - // compute standard deviation of it + // compute mean and standard deviation of diffs float sum = 0; float sumsq = 0; for (unsigned int i = 0; i < LEN; i ++) { diff --git a/code/valgrind/randomize.cpp b/code/valgrind/randomize.cpp index ff3e44f6..888f1976 100644 --- a/code/valgrind/randomize.cpp +++ b/code/valgrind/randomize.cpp @@ -13,7 +13,7 @@ void swap(int *a, int*b) { void randomize(int* v, unsigned int len) { std::default_random_engine e; - std::uniform_int_distribution d{0u, len}; + std::uniform_int_distribution d{0u, len - 1}; // we randomize via len random inversions for (unsigned int i = 0; i < len; i++) { int a = d(e); @@ -22,25 +22,25 @@ void randomize(int* v, unsigned int len) { } } -void createAndFillVector(int** v, unsigned int len) { - *v = new int[len]; - for (unsigned int i = 0; i < len; i++) (*v)[i] = i*STEP; +void createAndFillVector(int*& v, unsigned int len) { + v = new int[len]; + for (unsigned int i = 0; i < len; i++) v[i] = i*STEP; } int main() { int *v; - // create and randomize vector - createAndFillVector(&v, LEN+1); + // create and randomize vector of LEN+1 numbers + createAndFillVector(v, LEN+1); randomize(v, LEN+1); - // compute diffs + // compute LEN diffs int *diffs = new int[LEN]; for (unsigned int i = 0; i < LEN; i++) diffs[i] = v[i+1] - v[i]; delete[] v; delete[] diffs; - // compute standard deviation of it + // compute mean and standard deviation of diffs float sum = 0; float sumsq = 0; for (unsigned int i = 0; i < LEN; i ++) { diff --git a/code/valgrind/solution/randomize.sol.cpp b/code/valgrind/solution/randomize.sol.cpp index 08a3c8ed..473c1922 100644 --- a/code/valgrind/solution/randomize.sol.cpp +++ b/code/valgrind/solution/randomize.sol.cpp @@ -13,7 +13,7 @@ void swap(int *a, int*b) { void randomize(int* v, unsigned int len) { std::default_random_engine e; - std::uniform_int_distribution d{0u, len}; + std::uniform_int_distribution d{0u, len - 1}; // we randomize via len random inversions for (unsigned int i = 0; i < len; i++) { int a = d(e); @@ -22,24 +22,24 @@ void randomize(int* v, unsigned int len) { } } -void createAndFillVector(int** v, unsigned int len) { - *v = new int[len]; - for (unsigned int i = 0; i < len; i++) (*v)[i] = i*STEP; +void createAndFillVector(int*& v, unsigned int len) { + v = new int[len]; + for (unsigned int i = 0; i < len; i++) v[i] = i*STEP; } int main() { int *v; - // create and randomize vector - createAndFillVector(&v, LEN+1); + // create and randomize vector of LEN+1 numbers + createAndFillVector(v, LEN+1); randomize(v, LEN+1); - // compute diffs + // compute LEN diffs int *diffs = new int[LEN]; for (unsigned int i = 0; i < LEN; i++) diffs[i] = v[i+1] - v[i]; delete[] v; - // compute standard deviation of it + // compute mean and standard deviation of diffs float sum = 0; float sumsq = 0; for (unsigned int i = 0; i < LEN; i ++) { From 6de11339d2e7a63a7ab9a2f5210ef1fd30775e25 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Tue, 16 May 2023 18:16:23 -0400 Subject: [PATCH 012/156] Rename executable from debug exercise to "debug". Now that the executable no longer randomises the vector, the old name might be confusing. --- code/debug/CMakeLists.txt | 6 +++--- code/debug/Makefile | 10 +++++----- code/debug/{randomize.cpp => debug.cpp} | 0 .../solution/{randomize.sol.cpp => debug.sol.cpp} | 0 4 files changed, 8 insertions(+), 8 deletions(-) rename code/debug/{randomize.cpp => debug.cpp} (100%) rename code/debug/solution/{randomize.sol.cpp => debug.sol.cpp} (100%) diff --git a/code/debug/CMakeLists.txt b/code/debug/CMakeLists.txt index 950f6eaf..2f7f0ac1 100644 --- a/code/debug/CMakeLists.txt +++ b/code/debug/CMakeLists.txt @@ -6,8 +6,8 @@ project( debug LANGUAGES CXX ) include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) # Create the user's executable. -add_executable( debug_randomize "randomize.cpp" ) +add_executable( debug "debug.cpp" ) # Create the "solution executable". -add_executable( debug_randomize.sol EXCLUDE_FROM_ALL "solution/randomize.sol.cpp" ) -add_dependencies( solution debug_randomize.sol ) +add_executable( debug.sol EXCLUDE_FROM_ALL "solution/debug.sol.cpp" ) +add_dependencies( solution debug.sol ) diff --git a/code/debug/Makefile b/code/debug/Makefile index 0fd5e8ba..077aadfa 100644 --- a/code/debug/Makefile +++ b/code/debug/Makefile @@ -1,11 +1,11 @@ -all: randomize -solution: randomize.sol +all: debug +solution: debug.sol clean: - rm -f *o randomize *~ randomize.sol core + rm -f *o debug *~ debug.sol core -randomize : randomize.cpp +debug : debug.cpp ${CXX} -std=c++17 -g -O0 -L. -o $@ $< -randomize.sol : solution/randomize.sol.cpp +debug.sol : solution/debug.sol.cpp ${CXX} -std=c++17 -g -O0 -Wall -Wextra -L. -o $@ $< diff --git a/code/debug/randomize.cpp b/code/debug/debug.cpp similarity index 100% rename from code/debug/randomize.cpp rename to code/debug/debug.cpp diff --git a/code/debug/solution/randomize.sol.cpp b/code/debug/solution/debug.sol.cpp similarity index 100% rename from code/debug/solution/randomize.sol.cpp rename to code/debug/solution/debug.sol.cpp From e5de9717446dc01671579357ac8f3b7802d09bed Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Tue, 16 May 2023 18:08:57 -0400 Subject: [PATCH 013/156] Simplify debug exercise. The previous version had a lot of code that took time to process. Here, we replace the random generator and shuffling of the vector by a reverse operation. In addition, we can now check that the result is correct using std::is_sorted. Also run clang-format with a new style file that will be merged in a future PR. Co-authored-by: Philippe Canal --- code/debug/README.md | 13 ++--- code/debug/debug.cpp | 78 ++++++++++++---------------- code/debug/solution/debug.sol.cpp | 84 ++++++++++++++----------------- 3 files changed, 73 insertions(+), 102 deletions(-) diff --git a/code/debug/README.md b/code/debug/README.md index 14377e79..820cdf85 100644 --- a/code/debug/README.md +++ b/code/debug/README.md @@ -2,13 +2,6 @@ * compile, run, see the crash * run it in gdb -* inspect backtrace, variables -* find problem and fix bug -* try stepping, breakpoints - - -### Go back to the "valgrind" exercise - -* check it with valgrind -* analyze the issue, see that the variance was biaised -* fix the issue +* inspect backtrace, variables to understand the problem +* try stepping through the code using 'step' and 'next', use breakpoints and continue to get familiar with gdb +* fix the bug diff --git a/code/debug/debug.cpp b/code/debug/debug.cpp index 966f6413..c7c2ac3b 100644 --- a/code/debug/debug.cpp +++ b/code/debug/debug.cpp @@ -1,56 +1,44 @@ +#include #include -#include -#include -constexpr auto LEN = 1000; -constexpr auto STEP = 7; - -void swap(int *a, int*b) { - int c = *a; - *a = *b; - *b = c; +void swap(int * a, int * b) +{ + int c = *a; + *a = *b; + *b = c; } -void randomize(int* v, unsigned int len) { - std::default_random_engine e; - std::uniform_int_distribution d{0u, len - 1}; - // we randomize via len random inversions - for (unsigned int i = 0; i < len; i++) { - int a = d(e); - int b = d(e); - swap(v+a, v+b); - } -} +void reverse(int * v, unsigned int len) +{ + for (unsigned int i = 0; i < (len + 1) / 2; i++) { + const int a = i; + const int b = len - 1 - i; -void createAndFillVector(int*& v, unsigned int len) { - v = new int[LEN]; - for (unsigned int i = 0; i < len; i++) v[i] = i*STEP; + swap(v + a, v + b); + } } -int main() { - int *v = nullptr; - // create and randomize vector of LEN+1 numbers - randomize(v, LEN+1); - createAndFillVector(v, LEN+1); +int * createAndFillVector(unsigned int len) +{ + auto v = new int[len]; + for (unsigned int i = 0; i < len; i++) { + v[i] = i; + } + return v; +} - // compute LEN diffs - int *diffs = new int[LEN]; - for (unsigned int i = 0; i < LEN; i++) - diffs[i] = v[i+1] - v[i]; +int main() +{ + constexpr auto arraySize = 100; + int * v = nullptr; + // create and reverse the vector of LEN numbers + reverse(v, 1000); + v = createAndFillVector(arraySize); - // compute mean and standard deviation of diffs - float sum = 0; - float sumsq = 0; - for (unsigned int i = 0; i < LEN; i ++) { - sum += diffs[i]; - sumsq += diffs[i]*diffs[i]; - } - float mean = sum/LEN; - float stddev = std::sqrt(sumsq/LEN - mean*mean) ; - std::cout << "Range = [0, " << STEP*LEN << "]\n" - << "Mean = " << mean - << "\nStdDev = " << stddev << '\n'; + // check if the revert worked: + const bool isReversed = std::is_sorted(v, v + arraySize, std::greater{}); + std::cout << "Vector reversed successfully: " << std::boolalpha + << isReversed << "\n"; - delete[] v; - delete[] diffs; + return isReversed ? 0 : 1; } diff --git a/code/debug/solution/debug.sol.cpp b/code/debug/solution/debug.sol.cpp index fdd32476..1cc0a198 100644 --- a/code/debug/solution/debug.sol.cpp +++ b/code/debug/solution/debug.sol.cpp @@ -1,56 +1,46 @@ +#include #include -#include -#include -constexpr auto LEN = 1000; -constexpr auto STEP = 7; - -void swap(int *a, int*b) { - int c = *a; - *a = *b; - *b = c; +void swap(int * a, int * b) +{ + int c = *a; + *a = *b; + *b = c; } -void randomize(int* v, unsigned int len) { - std::default_random_engine e; - std::uniform_int_distribution d{0u, len - 1}; - // we randomize via len random inversions - for (unsigned int i = 0; i < len; i++) { - int a = d(e); - int b = d(e); - swap(v+a, v+b); - } +void reverse(int * v, unsigned int len) +{ + for (unsigned int i = 0; i < (len + 1) / 2; i++) { + const int a = i; + const int b = len - 1 - i; + + swap(v + a, v + b); + } } -void createAndFillVector(int*& v, unsigned int len) { - v = new int[len]; - for (unsigned int i = 0; i < len; i++) v[i] = i*STEP; +int * createAndFillVector(unsigned int len) +{ + auto v = new int[len]; + for (unsigned int i = 0; i < len; i++) { + v[i] = i; + } + return v; } -int main() { - int *v = nullptr; - // create and randomize vector of LEN+1 numbers - createAndFillVector(v, LEN+1); - randomize(v, LEN+1); - - // compute LEN diffs - int *diffs = new int[LEN]; - for (unsigned int i = 0; i < LEN; i++) - diffs[i] = v[i+1] - v[i]; - - // compute mean and standard deviation of diffs - float sum = 0; - float sumsq = 0; - for (unsigned int i = 0; i < LEN; i ++) { - sum += diffs[i]; - sumsq += diffs[i]*diffs[i]; - } - float mean = sum/LEN; - float stddev = std::sqrt(sumsq/LEN - mean*mean) ; - std::cout << "Range = [0, " << STEP*LEN << "]\n" - << "Mean = " << mean - << "\nStdDev = " << stddev << '\n'; - - delete[] v; - delete[] diffs; +int main() +{ + constexpr auto arraySize = 100; + int * v = nullptr; + // create and reverse the vector of LEN numbers + v = createAndFillVector(arraySize); + reverse(v, arraySize); + + // check if the revert worked: + const bool isReversed = std::is_sorted(v, v + arraySize, std::greater{}); + std::cout << "Vector reversed successfully: " << std::boolalpha + << isReversed << "\n"; + + delete[] v; + + return isReversed ? 0 : 1; } From 0b0c98243b6145b72f51b10fa6a6172fc3db1374 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Tue, 16 May 2023 18:30:52 -0400 Subject: [PATCH 014/156] Use similar code as for debugger exercise in valgrind exercise. --- code/valgrind/CMakeLists.txt | 6 +-- code/valgrind/Makefile | 12 ++--- code/valgrind/README.md | 7 +-- code/valgrind/debug.cpp | 44 +++++++++++++++++++ code/valgrind/randomize.cpp | 55 ----------------------- code/valgrind/solution/debug.sol.cpp | 46 +++++++++++++++++++ code/valgrind/solution/randomize.sol.cpp | 56 ------------------------ 7 files changed, 103 insertions(+), 123 deletions(-) create mode 100644 code/valgrind/debug.cpp delete mode 100644 code/valgrind/randomize.cpp create mode 100644 code/valgrind/solution/debug.sol.cpp delete mode 100644 code/valgrind/solution/randomize.sol.cpp diff --git a/code/valgrind/CMakeLists.txt b/code/valgrind/CMakeLists.txt index 20ba2fa1..80df4f13 100644 --- a/code/valgrind/CMakeLists.txt +++ b/code/valgrind/CMakeLists.txt @@ -6,8 +6,8 @@ project( valgrind LANGUAGES CXX ) include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) # Create the user's executable. -add_executable( valgrind_randomize "randomize.cpp" ) +add_executable( valgrind "debug.cpp" ) # Create the "solution executable". -add_executable( valgrind_randomize.sol EXCLUDE_FROM_ALL "solution/randomize.sol.cpp" ) -add_dependencies( solution valgrind_randomize.sol ) +add_executable( valgrind.sol EXCLUDE_FROM_ALL "solution/debug.sol.cpp" ) +add_dependencies( solution valgrind.sol ) diff --git a/code/valgrind/Makefile b/code/valgrind/Makefile index d544eadb..077aadfa 100644 --- a/code/valgrind/Makefile +++ b/code/valgrind/Makefile @@ -1,11 +1,11 @@ -all: randomize -solution: randomize.sol +all: debug +solution: debug.sol clean: - rm -f *o randomize *~ randomize.sol core + rm -f *o debug *~ debug.sol core -randomize : randomize.cpp - ${CXX} -std=c++17 -g -O0 -Wall -Wextra -L. -o $@ $< +debug : debug.cpp + ${CXX} -std=c++17 -g -O0 -L. -o $@ $< -randomize.sol : solution/randomize.sol.cpp +debug.sol : solution/debug.sol.cpp ${CXX} -std=c++17 -g -O0 -Wall -Wextra -L. -o $@ $< diff --git a/code/valgrind/README.md b/code/valgrind/README.md index 991367c1..85b79570 100644 --- a/code/valgrind/README.md +++ b/code/valgrind/README.md @@ -1,6 +1,7 @@ ## Instructions -* compile, run, it should work -* run with valgrind (`valgrind ./randomize`) -* fix the problem +* compile, run, it shouldn't crash +* run with valgrind (`valgrind ./debug`) +* fix an out-of-bounds access +* check for memory leaks diff --git a/code/valgrind/debug.cpp b/code/valgrind/debug.cpp new file mode 100644 index 00000000..3ec66137 --- /dev/null +++ b/code/valgrind/debug.cpp @@ -0,0 +1,44 @@ +#include +#include + +void swap(int * a, int * b) +{ + int c = *a; + *a = *b; + *b = c; +} + +void reverse(int * v, unsigned int len) +{ + for (unsigned int i = 0; i < (len + 1) / 2; i++) { + const int a = i; + const int b = len - i; + + swap(v + a, v + b); + } +} + +int * createAndFillVector(unsigned int len) +{ + auto v = new int[len]; + for (unsigned int i = 0; i < len; i++) { + v[i] = i; + } + return v; +} + +int main() +{ + constexpr auto arraySize = 100; + int * v = nullptr; + // create and reverse the vector of LEN numbers + v = createAndFillVector(arraySize); + reverse(v, arraySize); + + // check if the revert worked: + const bool isReversed = std::is_sorted(v, v + arraySize, std::greater{}); + std::cout << "Vector reversed successfully: " << std::boolalpha + << isReversed << "\n"; + + return isReversed ? 0 : 1; +} diff --git a/code/valgrind/randomize.cpp b/code/valgrind/randomize.cpp deleted file mode 100644 index 888f1976..00000000 --- a/code/valgrind/randomize.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include -#include - -constexpr auto LEN = 1000; -constexpr auto STEP = 7; - -void swap(int *a, int*b) { - int c = *a; - *a = *b; - *b = c; -} - -void randomize(int* v, unsigned int len) { - std::default_random_engine e; - std::uniform_int_distribution d{0u, len - 1}; - // we randomize via len random inversions - for (unsigned int i = 0; i < len; i++) { - int a = d(e); - int b = d(e); - swap(v+a, v+b); - } -} - -void createAndFillVector(int*& v, unsigned int len) { - v = new int[len]; - for (unsigned int i = 0; i < len; i++) v[i] = i*STEP; -} - -int main() { - int *v; - // create and randomize vector of LEN+1 numbers - createAndFillVector(v, LEN+1); - randomize(v, LEN+1); - - // compute LEN diffs - int *diffs = new int[LEN]; - for (unsigned int i = 0; i < LEN; i++) - diffs[i] = v[i+1] - v[i]; - delete[] v; - delete[] diffs; - - // compute mean and standard deviation of diffs - float sum = 0; - float sumsq = 0; - for (unsigned int i = 0; i < LEN; i ++) { - sum += diffs[i]; - sumsq += diffs[i]*diffs[i]; - } - float mean = sum/LEN; - float stddev = std::sqrt(sumsq/LEN - mean*mean) ; - std::cout << "Range = [0, " << STEP*LEN << "]\n" - << "Mean = " << mean - << "\nStdDev = " << stddev << '\n'; -} diff --git a/code/valgrind/solution/debug.sol.cpp b/code/valgrind/solution/debug.sol.cpp new file mode 100644 index 00000000..1cc0a198 --- /dev/null +++ b/code/valgrind/solution/debug.sol.cpp @@ -0,0 +1,46 @@ +#include +#include + +void swap(int * a, int * b) +{ + int c = *a; + *a = *b; + *b = c; +} + +void reverse(int * v, unsigned int len) +{ + for (unsigned int i = 0; i < (len + 1) / 2; i++) { + const int a = i; + const int b = len - 1 - i; + + swap(v + a, v + b); + } +} + +int * createAndFillVector(unsigned int len) +{ + auto v = new int[len]; + for (unsigned int i = 0; i < len; i++) { + v[i] = i; + } + return v; +} + +int main() +{ + constexpr auto arraySize = 100; + int * v = nullptr; + // create and reverse the vector of LEN numbers + v = createAndFillVector(arraySize); + reverse(v, arraySize); + + // check if the revert worked: + const bool isReversed = std::is_sorted(v, v + arraySize, std::greater{}); + std::cout << "Vector reversed successfully: " << std::boolalpha + << isReversed << "\n"; + + delete[] v; + + return isReversed ? 0 : 1; +} diff --git a/code/valgrind/solution/randomize.sol.cpp b/code/valgrind/solution/randomize.sol.cpp deleted file mode 100644 index 473c1922..00000000 --- a/code/valgrind/solution/randomize.sol.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include -#include - -constexpr auto LEN = 1000; -constexpr auto STEP = 7; - -void swap(int *a, int*b) { - int c = *a; - *a = *b; - *b = c; -} - -void randomize(int* v, unsigned int len) { - std::default_random_engine e; - std::uniform_int_distribution d{0u, len - 1}; - // we randomize via len random inversions - for (unsigned int i = 0; i < len; i++) { - int a = d(e); - int b = d(e); - swap(v+a, v+b); - } -} - -void createAndFillVector(int*& v, unsigned int len) { - v = new int[len]; - for (unsigned int i = 0; i < len; i++) v[i] = i*STEP; -} - -int main() { - int *v; - // create and randomize vector of LEN+1 numbers - createAndFillVector(v, LEN+1); - randomize(v, LEN+1); - - // compute LEN diffs - int *diffs = new int[LEN]; - for (unsigned int i = 0; i < LEN; i++) - diffs[i] = v[i+1] - v[i]; - delete[] v; - - // compute mean and standard deviation of diffs - float sum = 0; - float sumsq = 0; - for (unsigned int i = 0; i < LEN; i ++) { - sum += diffs[i]; - sumsq += diffs[i]*diffs[i]; - } - delete[] diffs; - - float mean = sum/LEN; - float stddev = std::sqrt(sumsq/LEN - mean*mean) ; - std::cout << "Range = [0, " << STEP*LEN << "]\n" - << "Mean = " << mean - << "\nStdDev = " << stddev << '\n'; -} From 54c97ab60827c51881e5ebd2540fbcb38854d373 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Thu, 18 May 2023 17:55:03 -0400 Subject: [PATCH 015/156] Switch on all warnings in debug exercise. After refactoring, we can switch on all warnings. --- code/debug/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/debug/Makefile b/code/debug/Makefile index 077aadfa..d41fde73 100644 --- a/code/debug/Makefile +++ b/code/debug/Makefile @@ -5,7 +5,7 @@ clean: rm -f *o debug *~ debug.sol core debug : debug.cpp - ${CXX} -std=c++17 -g -O0 -L. -o $@ $< + ${CXX} -std=c++17 -g -O0 -Wall -Wextra -L. -o $@ $< debug.sol : solution/debug.sol.cpp ${CXX} -std=c++17 -g -O0 -Wall -Wextra -L. -o $@ $< From 560e5273ccf1f072d838c19f9a18212b4acf75d4 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Mon, 15 May 2023 22:08:41 -0400 Subject: [PATCH 016/156] Add extra slide for static section. The code was a bit too short for explaining usage of a static member. --- talk/objectorientation/static.tex | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/talk/objectorientation/static.tex b/talk/objectorientation/static.tex index 00cffd62..dcc0dd51 100644 --- a/talk/objectorientation/static.tex +++ b/talk/objectorientation/static.tex @@ -9,15 +9,35 @@ \item identified by the \cppinline{static} keyword \end{itemize} \end{block} + + \vspace{-1\baselineskip} + \begin{overprint} + \onslide<1> + \begin{exampleblock}{Static.hpp} \begin{cppcode} class Text { public: - static std::string upper(std::string) {...} + static std::string upper(std::string); private: static int callsToUpper; // add `inline` in C++17 }; + \end{cppcode} + \end{exampleblock} + + \onslide<2> + \begin{exampleblock}{Static.cpp} + \begin{cppcode} + #include "Static.hpp" int Text::callsToUpper = 0; // required before C++17 + + std::string Text::upper(std::string lower) { + callsToUpper++; + // convert lower to upper case + // return ...; + } std::string uppers = Text::upper("my text"); // now Text::callsToUpper is 1 \end{cppcode} + \end{exampleblock} + \end{overprint} \end{frame} From aeea149fdcd2fb794a4f9e8a969c79f0d879b207 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Wed, 17 May 2023 11:41:29 -0400 Subject: [PATCH 017/156] Fix a wrong map::insert in STL chapter. We need to insert value_type, which is the pair --- talk/morelanguage/stl.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/talk/morelanguage/stl.tex b/talk/morelanguage/stl.tex index c806d11b..09b1b757 100644 --- a/talk/morelanguage/stl.tex +++ b/talk/morelanguage/stl.tex @@ -132,7 +132,7 @@ std::unordered_map m; m["hello"] = 1; // inserts new key, def. constr. value m["hello"] = 2; // finds existing key - auto [it, isNewKey] = m.insert("hello"); + auto [it, isNewKey] = m.insert({"hello", 0}); // no effect int val = m["world"]; // inserts new key (val == 0) int val = m.at("monde"); // throws std::out_of_range From 63be107373578b7fffb35dc1a6ac5facbb9f4741 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Wed, 17 May 2023 11:58:47 -0400 Subject: [PATCH 018/156] Use curly braces to create std::thread in RAII chapter. --- talk/morelanguage/raii.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/talk/morelanguage/raii.tex b/talk/morelanguage/raii.tex index c6492ff1..c305cb32 100644 --- a/talk/morelanguage/raii.tex +++ b/talk/morelanguage/raii.tex @@ -37,8 +37,8 @@ read_line(s); vec.push_back(s); set.add(s); - std::thread t1(func1, vec); - std::thread t2(func2, set); + std::thread t1{func1, vec}; + std::thread t2{func2, set}; \end{cppcode*} \end{exampleblock} \end{frame} From 1a6261be25589d67f7fd22ed2d45e96e44a32da4 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Thu, 18 May 2023 18:10:07 -0400 Subject: [PATCH 019/156] Add a clang-format style file. The style is based on WebKit, which looked to be closest to what we were using before. No style changes have been applied yet, but files can be formatted when they are worked on. --- code/.clang-format | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 code/.clang-format diff --git a/code/.clang-format b/code/.clang-format new file mode 100644 index 00000000..182c5b70 --- /dev/null +++ b/code/.clang-format @@ -0,0 +1,3 @@ +BasedOnStyle: WebKit +InsertNewlineAtEOF: True +Standard: Latest From 6a39b40a5a3cffc8c14d546b8159e48ea358af08 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Mon, 22 May 2023 13:22:30 +0200 Subject: [PATCH 020/156] [NFC] Apply clang-format to recently updated debug/valgrind exercise. --- code/debug/debug.cpp | 52 +++++++++++++-------------- code/debug/solution/debug.sol.cpp | 54 ++++++++++++++-------------- code/valgrind/debug.cpp | 52 +++++++++++++-------------- code/valgrind/solution/debug.sol.cpp | 54 ++++++++++++++-------------- 4 files changed, 106 insertions(+), 106 deletions(-) diff --git a/code/debug/debug.cpp b/code/debug/debug.cpp index c7c2ac3b..a09da9de 100644 --- a/code/debug/debug.cpp +++ b/code/debug/debug.cpp @@ -1,44 +1,44 @@ #include #include -void swap(int * a, int * b) +void swap(int* a, int* b) { - int c = *a; - *a = *b; - *b = c; + int c = *a; + *a = *b; + *b = c; } -void reverse(int * v, unsigned int len) +void reverse(int* v, unsigned int len) { - for (unsigned int i = 0; i < (len + 1) / 2; i++) { - const int a = i; - const int b = len - 1 - i; + for (unsigned int i = 0; i < (len + 1) / 2; i++) { + const int a = i; + const int b = len - 1 - i; - swap(v + a, v + b); - } + swap(v + a, v + b); + } } -int * createAndFillVector(unsigned int len) +int* createAndFillVector(unsigned int len) { - auto v = new int[len]; - for (unsigned int i = 0; i < len; i++) { - v[i] = i; - } - return v; + auto v = new int[len]; + for (unsigned int i = 0; i < len; i++) { + v[i] = i; + } + return v; } int main() { - constexpr auto arraySize = 100; - int * v = nullptr; - // create and reverse the vector of LEN numbers - reverse(v, 1000); - v = createAndFillVector(arraySize); + constexpr auto arraySize = 100; + int* v = nullptr; + // create and reverse the vector of LEN numbers + reverse(v, 1000); + v = createAndFillVector(arraySize); - // check if the revert worked: - const bool isReversed = std::is_sorted(v, v + arraySize, std::greater{}); - std::cout << "Vector reversed successfully: " << std::boolalpha - << isReversed << "\n"; + // check if the revert worked: + const bool isReversed = std::is_sorted(v, v + arraySize, std::greater {}); + std::cout << "Vector reversed successfully: " << std::boolalpha + << isReversed << "\n"; - return isReversed ? 0 : 1; + return isReversed ? 0 : 1; } diff --git a/code/debug/solution/debug.sol.cpp b/code/debug/solution/debug.sol.cpp index 1cc0a198..5676e620 100644 --- a/code/debug/solution/debug.sol.cpp +++ b/code/debug/solution/debug.sol.cpp @@ -1,46 +1,46 @@ #include #include -void swap(int * a, int * b) +void swap(int* a, int* b) { - int c = *a; - *a = *b; - *b = c; + int c = *a; + *a = *b; + *b = c; } -void reverse(int * v, unsigned int len) +void reverse(int* v, unsigned int len) { - for (unsigned int i = 0; i < (len + 1) / 2; i++) { - const int a = i; - const int b = len - 1 - i; + for (unsigned int i = 0; i < (len + 1) / 2; i++) { + const int a = i; + const int b = len - 1 - i; - swap(v + a, v + b); - } + swap(v + a, v + b); + } } -int * createAndFillVector(unsigned int len) +int* createAndFillVector(unsigned int len) { - auto v = new int[len]; - for (unsigned int i = 0; i < len; i++) { - v[i] = i; - } - return v; + auto v = new int[len]; + for (unsigned int i = 0; i < len; i++) { + v[i] = i; + } + return v; } int main() { - constexpr auto arraySize = 100; - int * v = nullptr; - // create and reverse the vector of LEN numbers - v = createAndFillVector(arraySize); - reverse(v, arraySize); + constexpr auto arraySize = 100; + int* v = nullptr; + // create and reverse the vector of LEN numbers + v = createAndFillVector(arraySize); + reverse(v, arraySize); - // check if the revert worked: - const bool isReversed = std::is_sorted(v, v + arraySize, std::greater{}); - std::cout << "Vector reversed successfully: " << std::boolalpha - << isReversed << "\n"; + // check if the revert worked: + const bool isReversed = std::is_sorted(v, v + arraySize, std::greater {}); + std::cout << "Vector reversed successfully: " << std::boolalpha + << isReversed << "\n"; - delete[] v; + delete[] v; - return isReversed ? 0 : 1; + return isReversed ? 0 : 1; } diff --git a/code/valgrind/debug.cpp b/code/valgrind/debug.cpp index 3ec66137..eb7a917a 100644 --- a/code/valgrind/debug.cpp +++ b/code/valgrind/debug.cpp @@ -1,44 +1,44 @@ #include #include -void swap(int * a, int * b) +void swap(int* a, int* b) { - int c = *a; - *a = *b; - *b = c; + int c = *a; + *a = *b; + *b = c; } -void reverse(int * v, unsigned int len) +void reverse(int* v, unsigned int len) { - for (unsigned int i = 0; i < (len + 1) / 2; i++) { - const int a = i; - const int b = len - i; + for (unsigned int i = 0; i < (len + 1) / 2; i++) { + const int a = i; + const int b = len - i; - swap(v + a, v + b); - } + swap(v + a, v + b); + } } -int * createAndFillVector(unsigned int len) +int* createAndFillVector(unsigned int len) { - auto v = new int[len]; - for (unsigned int i = 0; i < len; i++) { - v[i] = i; - } - return v; + auto v = new int[len]; + for (unsigned int i = 0; i < len; i++) { + v[i] = i; + } + return v; } int main() { - constexpr auto arraySize = 100; - int * v = nullptr; - // create and reverse the vector of LEN numbers - v = createAndFillVector(arraySize); - reverse(v, arraySize); + constexpr auto arraySize = 100; + int* v = nullptr; + // create and reverse the vector of LEN numbers + v = createAndFillVector(arraySize); + reverse(v, arraySize); - // check if the revert worked: - const bool isReversed = std::is_sorted(v, v + arraySize, std::greater{}); - std::cout << "Vector reversed successfully: " << std::boolalpha - << isReversed << "\n"; + // check if the revert worked: + const bool isReversed = std::is_sorted(v, v + arraySize, std::greater {}); + std::cout << "Vector reversed successfully: " << std::boolalpha + << isReversed << "\n"; - return isReversed ? 0 : 1; + return isReversed ? 0 : 1; } diff --git a/code/valgrind/solution/debug.sol.cpp b/code/valgrind/solution/debug.sol.cpp index 1cc0a198..5676e620 100644 --- a/code/valgrind/solution/debug.sol.cpp +++ b/code/valgrind/solution/debug.sol.cpp @@ -1,46 +1,46 @@ #include #include -void swap(int * a, int * b) +void swap(int* a, int* b) { - int c = *a; - *a = *b; - *b = c; + int c = *a; + *a = *b; + *b = c; } -void reverse(int * v, unsigned int len) +void reverse(int* v, unsigned int len) { - for (unsigned int i = 0; i < (len + 1) / 2; i++) { - const int a = i; - const int b = len - 1 - i; + for (unsigned int i = 0; i < (len + 1) / 2; i++) { + const int a = i; + const int b = len - 1 - i; - swap(v + a, v + b); - } + swap(v + a, v + b); + } } -int * createAndFillVector(unsigned int len) +int* createAndFillVector(unsigned int len) { - auto v = new int[len]; - for (unsigned int i = 0; i < len; i++) { - v[i] = i; - } - return v; + auto v = new int[len]; + for (unsigned int i = 0; i < len; i++) { + v[i] = i; + } + return v; } int main() { - constexpr auto arraySize = 100; - int * v = nullptr; - // create and reverse the vector of LEN numbers - v = createAndFillVector(arraySize); - reverse(v, arraySize); + constexpr auto arraySize = 100; + int* v = nullptr; + // create and reverse the vector of LEN numbers + v = createAndFillVector(arraySize); + reverse(v, arraySize); - // check if the revert worked: - const bool isReversed = std::is_sorted(v, v + arraySize, std::greater{}); - std::cout << "Vector reversed successfully: " << std::boolalpha - << isReversed << "\n"; + // check if the revert worked: + const bool isReversed = std::is_sorted(v, v + arraySize, std::greater {}); + std::cout << "Vector reversed successfully: " << std::boolalpha + << isReversed << "\n"; - delete[] v; + delete[] v; - return isReversed ? 0 : 1; + return isReversed ? 0 : 1; } From 22c6ca6ce627dd6a842f06409c463edb96f4af8f Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Thu, 9 Mar 2023 15:52:53 +0100 Subject: [PATCH 021/156] Allow for choosing essentials vs full via environment variable. - Move to -usepretex as a method to choose essentials vs full This defines a macro \makebasic, which is used to correctly initialise \ifbasic. It's necessary to define this macro upfront, since the \ifbasic is defined after the pretex commands run. - Modify Makefile to switch to essentials using e.g.: - make essentials - make HEPCPP_ESSENTIALS=1 - export HEPCPP_ESSENTIALS=1 make --- .github/workflows/build-slides.yml | 13 ++++++++++--- talk/C++Course.tex | 15 +++++++++++++-- talk/Makefile | 6 +++++- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-slides.yml b/.github/workflows/build-slides.yml index 3ecb3895..abcb3fb3 100644 --- a/.github/workflows/build-slides.yml +++ b/.github/workflows/build-slides.yml @@ -22,11 +22,18 @@ jobs: steps: - name: Set up Git repository uses: actions/checkout@v3 - - name: Set up essentials course + - name: Compile essentials + uses: xu-cheng/latex-action@v2 if: matrix.version == 'essentials' - run: echo '\basictrue' > talk/onlybasics.tex - - name: Compile LaTeX document + with: + root_file: C++Course.tex + latexmk_shell_escape: true + args: -pdf -interaction=nonstopmode -halt-on-error -usepretex=\def\makebasic{} + working_directory: talk + extra_system_packages: "py-pygments" + - name: Compile full course uses: xu-cheng/latex-action@v2 + if: matrix.version == 'full' with: root_file: C++Course.tex latexmk_shell_escape: true diff --git a/talk/C++Course.tex b/talk/C++Course.tex index 45f8bcd1..9af6c59c 100644 --- a/talk/C++Course.tex +++ b/talk/C++Course.tex @@ -7,8 +7,19 @@ % setup for the basic/advanced course switch % create a new latex if called basic (false by default) \newif\ifbasic -%\basictrue % uncomment to make basic true -\IfFileExists{onlybasics.tex}{\input{onlybasics}}{} + +% There are two ways to switch to the basic course: +% 1. Uncomment the following line: +%\basictrue + +% 2. Define the makebasic macro from the outside. +% This could be done using -usepretex=\def\makebasic{} +% The above is used: +% - when invoking "make essentials" +% - when exporting HEPCPP_ESSENTIALS=1 +\ifdefined\makebasic + \basictrue +\fi % create a comment environment advanced. depending on the value of basic, we exclude or include it. \ifbasic diff --git a/talk/Makefile b/talk/Makefile index 55c8d463..ad26716e 100644 --- a/talk/Makefile +++ b/talk/Makefile @@ -4,7 +4,7 @@ LATEXMK=latexmk OPTIONS=-pdf -shell-escape -halt-on-error essentials: all -essentials: OPTIONS+=-pretex='\basictrue' +essentials: OPTIONS+=-usepretex='\def\makebasic{}' preview: all preview: OPTIONS+=-pvc @@ -15,6 +15,10 @@ else OPTIONS+=-interaction=nonstopmode endif +ifeq ($(HEPCPP_ESSENTIALS), 1) + OPTIONS+=-usepretex='\def\makebasic{}' +endif + .PHONY: clean clobber FORCE %.pdf: %.tex FORCE From 2ddb6438bf7ce64cb96f081fa6c916b716909c97 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 10 Mar 2023 11:57:22 +0100 Subject: [PATCH 022/156] Fix a few spacing issues. Use xspace to fix space problems after \cpp. --- talk/morelanguage/templates.tex | 2 +- talk/setup.tex | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/talk/morelanguage/templates.tex b/talk/morelanguage/templates.tex index df69828f..52c492a2 100644 --- a/talk/morelanguage/templates.tex +++ b/talk/morelanguage/templates.tex @@ -108,7 +108,7 @@ \begin{frame}[fragile] \frametitlecpp[98]{Template parameters} - \begin{block}{\texttt{typename} vs. \texttt{class} keyword} + \begin{block}{\texttt{typename} vs.\ \texttt{class} keyword} \begin{itemize} \item for declaring a template type parameter, the \cppinline{typename} and \cppinline{class} keyword are semantically equivalent diff --git a/talk/setup.tex b/talk/setup.tex index c4cc7dec..34c4dafe 100644 --- a/talk/setup.tex +++ b/talk/setup.tex @@ -92,6 +92,7 @@ \usepackage{booktabs} \usepackage{comment} \usepackage{totcount} +\usepackage{xspace} % Use C++Course.cut for output so it's cleaned by latexmk \def\DefaultCutFileName{\def\CommentCutFile{\jobname.cut}} @@ -100,7 +101,7 @@ %%%%%%%%%%%%%%%%%%% % useful commands % %%%%%%%%%%%%%%%%%%% -\newcommand{\cpp}{C$^{++}$} +\newcommand{\cpp}{C$^{++}$\xspace} \newcommand{\deprecated}{\textcolor{red}{\bf Deprecated}} \newcommand{\removed}{\textcolor{red}{\bf Removed}} From 8f2959cea8dab0fc6aaeab217c9f13a91dfb2dd7 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Thu, 18 May 2023 19:05:09 -0400 Subject: [PATCH 023/156] Implement third way to switch to essentials course. On request, add a third way to switch to essentials using the existence or absence of a file: touch ./buildbasic --- talk/C++Course.tex | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/talk/C++Course.tex b/talk/C++Course.tex index 9af6c59c..855061a2 100644 --- a/talk/C++Course.tex +++ b/talk/C++Course.tex @@ -8,18 +8,18 @@ % create a new latex if called basic (false by default) \newif\ifbasic -% There are two ways to switch to the basic course: -% 1. Uncomment the following line: +% There are three ways to switch to the basic course: +% 1. Uncomment the line below. Disadvantage: git diff won't be empty %\basictrue - -% 2. Define the makebasic macro from the outside. -% This could be done using -usepretex=\def\makebasic{} -% The above is used: -% - when invoking "make essentials" -% - when exporting HEPCPP_ESSENTIALS=1 +% 2. Tell it to the Makefile. +% 2.1 Invoke "make essentials" +% 2.2 export HEPCPP_ESSENTIALS=1 +% make \ifdefined\makebasic \basictrue \fi +% 3. Create a file named ./buildbasic +\IfFileExists{./buildbasic}{\basictrue} % create a comment environment advanced. depending on the value of basic, we exclude or include it. \ifbasic From 756fd1801f420fe825fdd1d43084e16b054b951a Mon Sep 17 00:00:00 2001 From: Bernhard Manfred Gruber Date: Thu, 18 May 2023 10:53:06 -0400 Subject: [PATCH 024/156] Improve clarity of constness exercise * Rename functions to more meaningful names * Extent instructions to tell students to only change lines inside the main function --- code/constness/README.md | 2 +- code/constness/constplay.cpp | 38 ++++++++++++++++++------------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/code/constness/README.md b/code/constness/README.md index 991daa9e..74ac1d68 100644 --- a/code/constness/README.md +++ b/code/constness/README.md @@ -2,5 +2,5 @@ ## Instructions * open `constplay.cpp` -* try to find out which lines will be problematic +* try to find out which lines inside `main` will be problematic and comment them out * try to compile and check your findings diff --git a/code/constness/constplay.cpp b/code/constness/constplay.cpp index 2ce465b4..1af73941 100644 --- a/code/constness/constplay.cpp +++ b/code/constness/constplay.cpp @@ -1,23 +1,23 @@ #include #include -int identity(int a) { - return a; +void copy(int a) { + [[maybe_unused]] int val = a; }; -int identityConst(const int a) { - return a; +void copyConst(const int a) { + [[maybe_unused]] int val = a; }; -int* identityp(int* a) { - return a; +void write(int* a) { + *a = 42; }; -const int* identitypConst(const int *a) { - return a; +void read(const int *a) { + [[maybe_unused]] int val = *a; }; -struct ConstTest { +struct Test { void hello(std::string &s) { std::cout << "Hello " << s << '\n'; } @@ -46,22 +46,22 @@ int main() { // try constant arguments of functions int l = 0; const int m = 0; - identity(l); - identity(m); - identityConst(l); - identityConst(m); + copy(l); + copy(m); + copyConst(l); + copyConst(m); // try constant arguments of functions with pointers int *p = 0; const int *r = 0; - identityp(p); - identityp(r); - identitypConst(p); - identitypConst(r); + write(p); + write(r); + read(p); + read(r); // try constant method in a class - ConstTest t; - const ConstTest tc; + Test t; + const Test tc; std::string s("World"); t.hello(s); tc.hello(s); From e06969499c49c055f21ea50afa4962e5cd006122 Mon Sep 17 00:00:00 2001 From: Bernhard Manfred Gruber Date: Fri, 19 May 2023 09:58:11 +0200 Subject: [PATCH 025/156] Update code/constness/constplay.cpp Co-authored-by: Stephan Hageboeck --- code/constness/constplay.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/constness/constplay.cpp b/code/constness/constplay.cpp index 1af73941..ab3b9a04 100644 --- a/code/constness/constplay.cpp +++ b/code/constness/constplay.cpp @@ -1,6 +1,10 @@ #include #include +/* This is a dummy function to demonstrate pass by value. + * Since it doesn't do anything with the argument, we suppress + * possible compiler warnings using `maybe_unused`. + */ void copy(int a) { [[maybe_unused]] int val = a; }; From c2c3b2fdbad4c729fa14c1a7060c4fc284340774 Mon Sep 17 00:00:00 2001 From: Bernhard Manfred Gruber Date: Tue, 16 May 2023 15:44:29 -0400 Subject: [PATCH 026/156] Add some useful gdb commands --- code/debug/README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/code/debug/README.md b/code/debug/README.md index 820cdf85..4fec057a 100644 --- a/code/debug/README.md +++ b/code/debug/README.md @@ -5,3 +5,24 @@ * inspect backtrace, variables to understand the problem * try stepping through the code using 'step' and 'next', use breakpoints and continue to get familiar with gdb * fix the bug + +### Some useful gdb commands + +| Command | Effect | +|---------------------------|---------------------------------------------------------------| +| `gdb ./randomize` | launch the debugger with the given executable | +| `gdb --tui ./randomize` | same as above, but with terminal user interface enabled | +| `tui enable` | enabled the terminal user interface | +| `run` | runs the program | +| `bt, backtrace` | show a backtrace (list of stack frames) of the current thread | +| `up` | navigate one stack frame up | +| `down` | navigate one stack frame down | +| `s, step` | execute current line, stop at earliest next occasion | +| `n, next` | continue until next line or function exits | +| `c, continue` | continue execution | +| `print ` | show current value of variable | +| `info locals` | show the values of all local variables | +| `info args` | show the values of all function arguments | +| `br ` | put a breakpoint at line | +| `info br`: | list active breakpoints | +| `enable/disable/delete #` | enable/disable/delete breakpoints | From f2b3de77959c17b00927b9eef7c2363e6101dd94 Mon Sep 17 00:00:00 2001 From: Bernhard Manfred Gruber Date: Tue, 16 May 2023 11:49:16 -0400 Subject: [PATCH 027/156] OO fixes after JLab course Addresses part of #428 --- talk/basicconcepts/arrayspointers.tex | 24 +++++- talk/morelanguage/constness.tex | 2 +- talk/objectorientation/advancedoo.tex | 9 +-- talk/objectorientation/allocations.tex | 2 +- talk/objectorientation/constructors.tex | 97 +++++++++++------------ talk/objectorientation/functors.tex | 4 +- talk/objectorientation/objectsclasses.tex | 82 ++++++++++++------- 7 files changed, 128 insertions(+), 92 deletions(-) diff --git a/talk/basicconcepts/arrayspointers.tex b/talk/basicconcepts/arrayspointers.tex index 74c9f3bd..90f99312 100644 --- a/talk/basicconcepts/arrayspointers.tex +++ b/talk/basicconcepts/arrayspointers.tex @@ -92,7 +92,7 @@ \end{frame} \begin{frame}[fragile] - \frametitlecpp[98]{Dynamic Arrays using C} + \frametitlecpp[98]{Dynamic arrays using C} \begin{cppcode} #include #include @@ -112,3 +112,25 @@ Use \cppinline{std::vector} and friends or smart pointers \end{goodpracticeWithShortcut} \end{frame} + +\begin{frame}[fragile] + \frametitlecpp[98]{Manual dynamic arrays using \cpp} + \begin{cppcode} + #include + #include + + // allocate array of 10 ints + int* ai = new int[10]; // uninitialized + int* ai = new int[10]{}; // zero-initialized + + delete[] ai; // release array memory + + // allocate a single int + int* pi = new int; + int* pi = new int{}; + delete pi; // release scalar memory + \end{cppcode} + \begin{goodpracticeWithShortcut}{Don't use manual memory management}{Manual memory management} + Use \cppinline{std::vector} and friends or smart pointers + \end{goodpracticeWithShortcut} +\end{frame} diff --git a/talk/morelanguage/constness.tex b/talk/morelanguage/constness.tex index 000003da..f5493a6a 100644 --- a/talk/morelanguage/constness.tex +++ b/talk/morelanguage/constness.tex @@ -73,7 +73,7 @@ \end{frame} \begin{frame}[fragile] - \frametitlecpp[98]{Method constness} + \frametitlecpp[98]{Member function constness} \begin{block}{Constness is part of the type} \begin{itemize} \item \cppinline{T const} and \cppinline{T} are different types diff --git a/talk/objectorientation/advancedoo.tex b/talk/objectorientation/advancedoo.tex index af7d0b9c..31ec8b90 100644 --- a/talk/objectorientation/advancedoo.tex +++ b/talk/objectorientation/advancedoo.tex @@ -267,7 +267,7 @@ \end{advanced} \begin{frame}[fragile] - \frametitlecpp[98]{Pure Virtual methods} + \frametitlecpp[11]{Pure Virtual methods} \begin{block}{Concept} \begin{itemize} \item unimplemented methods that must be overridden @@ -358,9 +358,7 @@ delete p; // dynamic dispatch to right destructor \end{cppcode} \begin{goodpractice}{Virtual destructors} - \begin{itemize} - \item If you expect users to inherit from your class and override methods (i.e.\ use your class polymorphically), declare its destructor \cppinline{virtual} - \end{itemize} + If you expect users to inherit from your class and override methods (i.e.\ use your class polymorphically), declare its destructor \cppinline{virtual} \end{goodpractice} \end{frame} @@ -380,7 +378,8 @@ \begin{multicols}{2} \begin{cppcode*}{gobble=2} struct Drawable { - virtual ~Drawable() = default; + virtual ~Drawable() + = default; virtual void draw() = 0; } \end{cppcode*} diff --git a/talk/objectorientation/allocations.tex b/talk/objectorientation/allocations.tex index 0d4462b9..d76ae1f3 100644 --- a/talk/objectorientation/allocations.tex +++ b/talk/objectorientation/allocations.tex @@ -99,7 +99,7 @@ } int g() { // constructor called - MyFirstClass *a = new MyFirstClass(3); + MyFirstClass *a = new MyFirstClass{3}; } // memory leak !!! \end{cppcode} \begin{goodpracticeWithShortcut}{Prefer smart pointers over new/delete}{Prefer smart pointer} diff --git a/talk/objectorientation/constructors.tex b/talk/objectorientation/constructors.tex index 0af6c1a3..6edcc0ad 100644 --- a/talk/objectorientation/constructors.tex +++ b/talk/objectorientation/constructors.tex @@ -1,7 +1,7 @@ \subsection[construct]{Constructors/destructors} \begin{frame}[fragile] - \frametitlecpp[98]{Class Constructors and Destructors} + \frametitlecpp[98]{Class constructors and destructors} \begin{block}{Concept} \begin{itemize} \item special functions called when building/destroying an object @@ -12,11 +12,11 @@ \end{block} \begin{multicols}{2} \begin{cppcode*}{gobble=2} - class MyFirstClass { + class C { public: - MyFirstClass(); - MyFirstClass(int a); - ~MyFirstClass(); + C(); + C(int a); + ~C(); ... protected: int a; @@ -26,18 +26,18 @@ \begin{cppcode*}{gobble=2,firstnumber=10} // note: special notation for // initialization of members - MyFirstClass() : a(0) {} + C::C() : a(0) {} - MyFirstClass(int a_):a(a_) {} + C::C(int a) : a(a) {} - ~MyFirstClass() {} + C::~C() {} \end{cppcode*} \end{multicols} \end{frame} \begin{frame}[fragile] - \frametitlecpp[98]{Class Constructors and Destructors} + \frametitlecpp[98]{Class constructors and destructors} \begin{cppcode} class Vector { public: @@ -61,22 +61,20 @@ \begin{frame}[fragile] \frametitlecpp[98]{Constructors and inheritance} \begin{cppcode} - struct MyFirstClass { + struct First { int a; - MyFirstClass(); - MyFirstClass(int a); + First() {} // leaves a uninitialized + First(int a) : a(a) {} }; - struct MySecondClass : MyFirstClass { + struct Second : First { int b; - MySecondClass(); - MySecondClass(int b); - MySecondClass(int a, int b); + Second(); + Second(int b); + Second(int a, int b); }; - MySecondClass::MySecondClass() : MyFirstClass(), b(0) {} - MySecondClass::MySecondClass(int b_) - : MyFirstClass(), b(b_) {} - MySecondClass::MySecondClass(int a_, int b_) - : MyFirstClass(a_), b(b_) {} + Second::Second() : First(), b(0) {} + Second::Second(int b) : b(b) {} // First() implicitly + Second::Second(int a, int b) : First(a), b(b) {} \end{cppcode} \end{frame} @@ -95,9 +93,9 @@ \end{block} \pause \begin{cppcode} - struct MySecondClass : MyFirstClass { - MySecondClass(); - MySecondClass(const MySecondClass &other); + struct C { + C(); + C(const C &other); }; \end{cppcode} \pause @@ -114,7 +112,8 @@ Vector(int n); Vector(const Vector &other); ~Vector(); - ... + private: + int len; int* data; }; Vector::Vector(int n) : len(n) { data = new int[n]; @@ -137,7 +136,7 @@ \begin{exampleblockGB}{Example}{https://godbolt.org/z/TvqT185fz}{Unary constructor in action} \begin{cppcode} void print(const Vector & v) { - std::cout<<"printing v elements...\n"; + std::cout << "printing v elements...\n"; } int main { @@ -224,14 +223,15 @@ \end{block} \begin{exampleblock}{Practically} \begin{cppcode} - struct BaseClass { - BaseClass(int a); + struct Base { + Base(int a); // ctor 1 }; - struct DerivedClass : BaseClass { - using BaseClass::BaseClass; - DerivedClass(int a, int b); + struct Derived : Base { + using Base::Base; + Derived(int a, int b); // ctor 2 }; - DerivedClass a{5}; + Derived d{5}; // calls ctor 1 + Derived d{5, 6}; // calls ctor 2 \end{cppcode} \end{exampleblock} \end{frame} @@ -246,16 +246,17 @@ \end{block} \begin{exampleblock}{Practically} \begin{cppcode} - struct BaseClass { + struct Base { int a{5}; // also possible: int a = 5; - BaseClass() = default; - BaseClass(int _a) : a(_a) {} + Base() = default; + Base(int _a) : a(_a) {} }; - struct DerivedClass : BaseClass { + struct Derived : Base { int b{6}; - using BaseClass::BaseClass; + using Base::Base; }; - DerivedClass d{7}; // a = 7, b = 6 + Derived d1; // a = 5, b = 6 + Derived d2{7}; // a = 7, b = 6 \end{cppcode} \end{exampleblock} \end{frame} @@ -295,29 +296,21 @@ A a(1,2); // A::A(int, int) A a(1); // A::A(int) - A a(); // declaration of a function ! + A a(); // declaration of a function! A a; // A::A() - A a = (1,2); // A::A(int), comma operator ! + A a = (1,2); // A::A(int), comma operator! A a = {1,2}; // not allowed \end{cppcode*} \end{block} \end{frame} \begin{frame}[fragile] - \frametitlecpp[11]{Calling constructors for arrays and vectors} - \begin{exampleblock}{list of items given within \{\}} + \frametitlecpp[11]{Constructing arrays and vectors} + \begin{exampleblock}{List of items given within \{\}} \begin{cppcode*}{firstnumber=10} int ip[3]{1,2,3}; - int* ip = new int[3]{1,2,3}; - std::vector v{1,2,3}; + int* ip = new int[3]{1,2,3}; // not allowed in C++98 + std::vector v{1,2,3}; // same \end{cppcode*} \end{exampleblock} - \pause - \begin{block}{\cpp98 nightmare} - \begin{cppcode*}{firstnumber=10} - int ip[3]{1,2,3}; // OK - int* ip = new int[3]{1,2,3}; // not allowed - std::vector v{1,2,3}; // not allowed - \end{cppcode*} - \end{block} \end{frame} diff --git a/talk/objectorientation/functors.tex b/talk/objectorientation/functors.tex index 242b0bde..b5b1d115 100644 --- a/talk/objectorientation/functors.tex +++ b/talk/objectorientation/functors.tex @@ -26,12 +26,12 @@ \begin{frame}[fragile] \frametitlecpp[20]{Function objects} - \begin{exampleblockGB}{Function objects as function arguments}{https://godbolt.org/z/1nqnfKxx8}{function objects} + \begin{exampleblockGB}{Function objects as function arguments}{https://godbolt.org/z/zxqYG6xzT}{function objects} \begin{cppcode} int count_if(const auto& range, auto predicate) { int count = 0; // ↑ template (later) for (const auto& e : range) - count += predicate(e); + if (predicate(e)) count++; return count; } struct IsBetween { diff --git a/talk/objectorientation/objectsclasses.tex b/talk/objectorientation/objectsclasses.tex index 1a248078..814b50a2 100644 --- a/talk/objectorientation/objectsclasses.tex +++ b/talk/objectorientation/objectsclasses.tex @@ -7,7 +7,7 @@ \begin{itemize} \item with inheritance \item with access control - \item including methods/member functions + \item including methods (aka.\ member functions) \end{itemize} \end{block} \begin{block}{Objects} @@ -65,37 +65,58 @@ \begin{frame}[fragile] \frametitlecpp[98]{Separating the interface} - \begin{block}{Header : MyFirstClass.hpp} - \begin{cppcode*}{} - #pragma once - struct MyFirstClass { - int a; - void squareA(); - int sum(int b); - }; - \end{cppcode*} - \end{block} - \begin{block}{Implementation : MyFirstClass.cpp} - \begin{cppcode*}{} - #include "MyFirstClass.hpp" - void MyFirstClass::squareA() { - a *= a; - } - int MyFirstClass::sum(int b) { - return a + b; - } - \end{cppcode*} - \end{block} + \begin{columns}[t] + \begin{column}{.45\textwidth} + \begin{block}{Header: MyClass.hpp} + \begin{cppcode*}{gobble=4} + #pragma once + struct MyClass { + int a; + void squareA(); + }; + \end{cppcode*} + \end{block} + \begin{block}{Implementation: MyClass.cpp} + \begin{cppcode*}{gobble=4} + #include "MyClass.hpp" + void MyClass::squareA() { + a *= a; + } + \end{cppcode*} + \end{block} + \end{column} + \begin{column}{.45\textwidth} + \begin{block}{User 1: main.cpp} + \begin{cppcode*}{gobble=4} + #include "MyClass.hpp" + int main() { + MyClass mc; + ... + } + \end{cppcode*} + \end{block} + \begin{block}{User 2: fun.cpp} + \begin{cppcode*}{gobble=4} + #include "MyClass.hpp" + void f(MyClass& mc) { + mc.squareA(); + } + \end{cppcode*} + \end{block} + \end{column} + \end{columns} \end{frame} \begin{frame}[fragile] \frametitlecpp[98]{Implementing methods} - \begin{block}{Standard practice} + \begin{goodpractice}{Implementing methods} \begin{itemize} \item usually in .cpp, outside of class declaration \item using the class name as ``namespace'' + \item short member functions can be in the header + \item some functions (templates, \cppinline{constexpr}) must be in the header \end{itemize} - \end{block} + \end{goodpractice} \begin{cppcode} void MyFirstClass::squareA() { a *= a; @@ -116,18 +137,19 @@ \item All class methods can use the keyword \cppinline{this} \begin{itemize} \item It returns the address of the current object - \item Its type is \cppinline{T*} in the methods of a struct/class {\ttfamily T} + \item Its type is \cppinline{T*} in the methods of a class {\ttfamily T} \end{itemize} \end{itemize} \end{block} \begin{cppcode} - void externalFunc(MyStruct & s); - - struct MyStruct { - void invokeExternalFunc() { - externalFunc(*this); // Pass a reference to ourself + void freeFunc(S & s); + struct S { + void memberFunc() { // Implicit S* parameter + freeFunc(*this); // Pass a reference to ourself } }; + S s; + s.memberFunc(); // Passes &s implicitly \end{cppcode} \end{frame} From b1101244ee621186e1dba9d1af1fd7d578060492 Mon Sep 17 00:00:00 2001 From: Bernhard Manfred Gruber Date: Thu, 18 May 2023 11:45:29 -0400 Subject: [PATCH 028/156] Clarify instructions of template exercise Some students in the JLab afternoon lecture tried to build a `Complex`. Make this less likely to happen again. Co-authored-by: Stephan Hageboeck --- code/ExercisesCheatSheet.md | 6 +++--- code/templates/README.md | 7 +++++-- code/templates/playwithsort.cpp | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/code/ExercisesCheatSheet.md b/code/ExercisesCheatSheet.md index d494f8da..a00cee71 100644 --- a/code/ExercisesCheatSheet.md +++ b/code/ExercisesCheatSheet.md @@ -107,11 +107,11 @@ See in valgrind the improvements. ### Generic programming / templates (directory: [`templates`](templates)) -This exercise has several levels. People not at ease can stop after first level and go to next exercise. Alternatively, they may do level 1 and 3 and skip 2. +This exercise has several levels. People not at ease can stop after the first level and go to next exercise. Alternatively, they may do level 1 and 3 and skip 2. -Level 1 : just use the given Complex class in OrderedVector and see it works out of the box thanks to generic code in OrderedVector. +Level 1: just use the given `Complex` alias (`Complex_t`) inside an `OrderedVector`, fill and print it. See that it works out of the box thanks to generic code in `OrderedVector`. -Level 2 : add a template argument for the ordering in OrderedVector. +Level 2: add a template argument for the ordering in OrderedVector. The idea is to add an extra template argument "Compare" that is a functor comparing 2 arguments and an extra member "m_compare" of type "Compare" to the OrderedVector class. Then the comparison in the add function can be replaced by ```cpp diff --git a/code/templates/README.md b/code/templates/README.md index 67b46a64..0b1289d0 100644 --- a/code/templates/README.md +++ b/code/templates/README.md @@ -3,8 +3,11 @@ Beginners * Look at the `OrderedVector` code -* Compile and run `playwithsort.cpp`. See the ordering -* Modify `playwithsort.cpp` and reuse `OrderedVector` with `Complex` +* Compile and run `playwithsort.cpp`. See the printed ordering +* Inspect the `Complex_t` class template and the alias `Complex`. + Then, in `playwithsort.cpp`, create a third `OrderedVector` with `Complex` as element type, + fill it with some complex values and print the vector. + No modifications to `Complex_t` and `OrderedVector` are required! Intermediary * Extend `OrderedVector` to allow to customize the ordering via an additional template parameter. diff --git a/code/templates/playwithsort.cpp b/code/templates/playwithsort.cpp index 41e52d89..3238a45d 100644 --- a/code/templates/playwithsort.cpp +++ b/code/templates/playwithsort.cpp @@ -37,7 +37,7 @@ int main() { std::cout << vs[i] << " "; std::cout << "\n\n"; - // TODO: Demonstrate OrderedVector with Complex as done above + // TODO: Demonstrate OrderedVector with Complex as element type similar to above // TODO: Extend OrderedVector to allow to customize the ordering via an additional template paramter. From 5a089cc294a95058de488656961bc993d998cbed Mon Sep 17 00:00:00 2001 From: Bernhard Manfred Gruber Date: Wed, 21 Jun 2023 18:45:04 +0200 Subject: [PATCH 029/156] Rename directory code to exercises Fixes: #456 --- .github/workflows/build-exercises.yml | 10 ++-- .gitignore | 48 +++++++++---------- README.md | 4 +- {code => exercises}/.clang-format | 0 {code => exercises}/CMakeLists.txt | 0 .../ExerciseSchedule_AdvancedCourse.md | 0 .../ExerciseSchedule_EssentialCourse.md | 0 {code => exercises}/ExercisesCheatSheet.md | 2 +- {code => exercises}/Makefile | 0 {code => exercises}/README.md | 12 ++--- {code => exercises}/asan/CMakeLists.txt | 0 {code => exercises}/asan/Makefile | 0 {code => exercises}/asan/README.md | 0 {code => exercises}/asan/asan.cpp | 0 .../asan/solution/asan.sol.cpp | 0 {code => exercises}/atomic/CMakeLists.txt | 0 {code => exercises}/atomic/Makefile | 0 {code => exercises}/atomic/README.md | 0 {code => exercises}/atomic/atomic.cpp | 0 .../atomic/solution/atomic.sol.cpp | 0 {code => exercises}/callgrind/CMakeLists.txt | 0 {code => exercises}/callgrind/Makefile | 0 {code => exercises}/callgrind/README.md | 0 {code => exercises}/callgrind/fibocrunch.cpp | 0 .../callgrind/solution/fibocrunch.sol.cpp | 0 {code => exercises}/check_setup.sh | 0 {code => exercises/code}/memcheck/README.md | 0 {code => exercises}/common.cmake | 0 {code => exercises}/concepts/CMakeLists.txt | 0 {code => exercises}/concepts/Makefile | 0 {code => exercises}/concepts/README.md | 0 {code => exercises}/concepts/concepts.cpp | 0 .../concepts/solution/concepts.sol1.cpp | 0 .../concepts/solution/concepts.sol2.cpp | 0 .../condition_variable/CMakeLists.txt | 0 .../condition_variable/Makefile | 0 .../condition_variable/condition_variable.cpp | 0 .../solution/condition_variable.sol.cpp | 0 {code => exercises}/constness/CMakeLists.txt | 0 {code => exercises}/constness/Makefile | 0 {code => exercises}/constness/README.md | 0 {code => exercises}/constness/constplay.cpp | 0 {code => exercises}/control/CMakeLists.txt | 0 {code => exercises}/control/Makefile | 0 {code => exercises}/control/README.md | 0 {code => exercises}/control/control.cpp | 0 .../control/solution/control.sol.cpp | 0 {code => exercises}/cppcheck/CMakeLists.txt | 0 {code => exercises}/cppcheck/Makefile | 0 {code => exercises}/cppcheck/README.md | 0 {code => exercises}/cppcheck/randomize.cpp | 0 .../cppcheck/solution/randomize.sol.cpp | 0 {code => exercises}/debug/CMakeLists.txt | 0 {code => exercises}/debug/Makefile | 0 {code => exercises}/debug/README.md | 0 {code => exercises}/debug/debug.cpp | 0 .../debug/solution/debug.sol.cpp | 0 {code => exercises}/functions/CMakeLists.txt | 0 {code => exercises}/functions/Makefile | 0 {code => exercises}/functions/README.md | 0 {code => exercises}/functions/Structs.cpp | 0 {code => exercises}/functions/Structs.h | 0 {code => exercises}/functions/functions.cpp | 0 .../functions/solution/functions.sol.cpp | 0 {code => exercises}/header_units/Complex.hpp | 0 {code => exercises}/header_units/Makefile | 0 {code => exercises}/header_units/README.md | 0 {code => exercises}/header_units/main.cpp | 0 .../header_units/solution/Makefile | 0 .../header_units/solution/main.cpp | 0 {code => exercises}/helgrind/CMakeLists.txt | 0 {code => exercises}/helgrind/Makefile | 0 {code => exercises}/helgrind/README.md | 0 {code => exercises}/helgrind/fiboMT.cpp | 0 .../helgrind/solution/fiboMT.sol.cpp | 0 {code => exercises}/hello/CMakeLists.txt | 0 {code => exercises}/hello/Makefile | 0 {code => exercises}/hello/README.md | 0 {code => exercises}/hello/hello.cpp | 0 {code => exercises}/hello/hello.hpp | 0 {code => exercises}/hello/main.cpp | 0 .../loopsRefsAuto/CMakeLists.txt | 0 {code => exercises}/loopsRefsAuto/Makefile | 0 {code => exercises}/loopsRefsAuto/README.md | 0 .../loopsRefsAuto/loopsRefsAuto.cpp | 0 .../solution/loopsRefsAuto.sol.cpp | 0 {code => exercises}/memcheck/CMakeLists.txt | 0 {code => exercises}/memcheck/Makefile | 0 {code => exercises}/memcheck/Polygons.cpp | 0 {code => exercises}/memcheck/Polygons.hpp | 0 exercises/memcheck/README.md | 0 {code => exercises}/memcheck/memleak.cpp | 0 .../memcheck/solution/Polygons.sol.cpp | 0 .../memcheck/solution/Polygons.sol.hpp | 0 .../memcheck/solution/memleak.sol.cpp | 0 {code => exercises}/modern_oo/CMakeLists.txt | 0 {code => exercises}/modern_oo/Makefile | 0 {code => exercises}/modern_oo/README.md | 0 {code => exercises}/modern_oo/particles.cpp | 0 .../modern_oo/solution/particles.sol.cpp | 0 {code => exercises}/modules/Complex.hpp | 0 {code => exercises}/modules/Makefile | 0 {code => exercises}/modules/README.md | 0 {code => exercises}/modules/main.cpp | 0 .../modules/solution/Complex.cpp | 0 {code => exercises}/modules/solution/Makefile | 0 {code => exercises}/modules/solution/main.cpp | 0 {code => exercises}/move/CMakeLists.txt | 0 {code => exercises}/move/Makefile | 0 {code => exercises}/move/README.md | 0 .../move/solution/trymove.sol.cpp | 0 {code => exercises}/move/trymove.cpp | 0 {code => exercises}/operators/CMakeLists.txt | 0 {code => exercises}/operators/Makefile | 0 {code => exercises}/operators/README.md | 0 {code => exercises}/operators/operators.cpp | 0 .../operators/solution/operators.sol.cpp | 0 {code => exercises}/optional/CMakeLists.txt | 0 {code => exercises}/optional/Makefile | 0 {code => exercises}/optional/README.md | 0 {code => exercises}/optional/optional.cpp | 0 .../optional/solution/optional.sol.cpp | 0 .../polymorphism/CMakeLists.txt | 0 {code => exercises}/polymorphism/Makefile | 0 {code => exercises}/polymorphism/Polygons.cpp | 0 {code => exercises}/polymorphism/Polygons.hpp | 0 {code => exercises}/polymorphism/README.md | 0 .../polymorphism/solution/trypoly.sol.cpp | 0 {code => exercises}/polymorphism/trypoly.cpp | 0 {code => exercises}/python/CMakeLists.txt | 0 {code => exercises}/python/Complex.hpp | 0 {code => exercises}/python/Makefile | 0 {code => exercises}/python/README.md | 0 {code => exercises}/python/mandel.cpp | 0 {code => exercises}/python/mandel.hpp | 0 {code => exercises}/python/mandel.py | 0 .../python/mandel_cwrapper.cpp | 0 .../python/mandel_cwrapper.hpp | 0 {code => exercises}/python/mandel_module.cpp | 0 .../python/solution/mandel.sol.py | 0 .../python/solution/mandel.solctype.py | 0 {code => exercises}/race/CMakeLists.txt | 0 {code => exercises}/race/Makefile | 0 {code => exercises}/race/README.md | 0 {code => exercises}/race/racing.cpp | 0 {code => exercises}/race/run | 0 .../race/solution/racing.sol.cpp | 0 .../smartPointers/CMakeLists.txt | 0 {code => exercises}/smartPointers/Makefile | 0 {code => exercises}/smartPointers/README.md | 0 .../smartPointers/smartPointers.cpp | 0 .../solution/smartPointers.sol.cpp | 0 {code => exercises}/spaceship/CMakeLists.txt | 0 {code => exercises}/spaceship/Makefile | 0 {code => exercises}/spaceship/README.md | 0 .../spaceship/solution/spaceship.sol.cpp | 0 {code => exercises}/spaceship/spaceship.cpp | 0 {code => exercises}/stl/CMakeLists.txt | 0 {code => exercises}/stl/Complex.hpp | 0 {code => exercises}/stl/Makefile | 0 {code => exercises}/stl/README.md | 0 {code => exercises}/stl/randomize.cpp | 0 {code => exercises}/stl/randomize.nostl.cpp | 0 .../stl/solution/randomize.sol.cpp | 0 {code => exercises}/templates/CMakeLists.txt | 0 {code => exercises}/templates/Complex.hpp | 0 {code => exercises}/templates/Makefile | 0 .../templates/OrderedVector.hpp | 0 {code => exercises}/templates/README.md | 0 .../templates/playwithsort.cpp | 0 .../templates/solution/OrderedVector.sol.hpp | 0 .../templates/solution/playwithsort.sol.cpp | 0 {code => exercises}/valgrind/CMakeLists.txt | 0 {code => exercises}/valgrind/Makefile | 0 {code => exercises}/valgrind/README.md | 0 {code => exercises}/valgrind/debug.cpp | 0 .../valgrind/solution/debug.sol.cpp | 0 {code => exercises}/variadic/CMakeLists.txt | 0 {code => exercises}/variadic/Makefile | 0 {code => exercises}/variadic/README.md | 0 .../variadic/solution/variadic.sol.cpp | 0 {code => exercises}/variadic/variadic.cpp | 0 {code => exercises}/variant/CMakeLists.txt | 0 {code => exercises}/variant/Makefile | 0 {code => exercises}/variant/README.md | 0 .../variant/solution/variant.sol1.cpp | 0 .../variant/solution/variant.sol2.cpp | 0 {code => exercises}/variant/variant.cpp | 0 .../virtual_inheritance/CMakeLists.txt | 0 .../virtual_inheritance/Makefile | 0 .../virtual_inheritance/README.md | 0 .../virtual_inheritance/TextBox.cpp | 0 .../virtual_inheritance/TextBox.hpp | 0 .../virtual_inheritance/solution/TextBox.cpp | 0 .../virtual_inheritance/solution/TextBox.hpp | 0 .../solution/trymultiherit.sol.cpp | 0 .../virtual_inheritance/trymultiherit.cpp | 0 talk/basicconcepts/auto.tex | 2 +- talk/basicconcepts/control.tex | 2 +- talk/basicconcepts/functions.tex | 2 +- talk/concurrency/atomic.tex | 2 +- talk/concurrency/condition.tex | 2 +- talk/concurrency/mutexes.tex | 4 +- talk/expert/cpp20concepts.tex | 2 +- talk/expert/modules.tex | 4 +- talk/expert/variadictemplate.tex | 2 +- talk/morelanguage/constness.tex | 2 +- talk/morelanguage/morestl.tex | 4 +- talk/morelanguage/move.tex | 2 +- talk/morelanguage/raii.tex | 2 +- talk/morelanguage/stl.tex | 2 +- talk/morelanguage/templates.tex | 2 +- talk/objectorientation/advancedoo.tex | 4 +- talk/objectorientation/operators.tex | 2 +- talk/python/ctypes.tex | 2 +- talk/python/modulewriting.tex | 6 +-- talk/tools/compiling.tex | 2 +- talk/tools/debugging.tex | 2 +- talk/tools/formatting.tex | 2 +- talk/tools/sanitizers.tex | 2 +- talk/tools/staticanalysis.tex | 4 +- talk/tools/valgrind.tex | 10 ++-- 222 files changed, 74 insertions(+), 74 deletions(-) rename {code => exercises}/.clang-format (100%) rename {code => exercises}/CMakeLists.txt (100%) rename {code => exercises}/ExerciseSchedule_AdvancedCourse.md (100%) rename {code => exercises}/ExerciseSchedule_EssentialCourse.md (100%) rename {code => exercises}/ExercisesCheatSheet.md (99%) rename {code => exercises}/Makefile (100%) rename {code => exercises}/README.md (97%) rename {code => exercises}/asan/CMakeLists.txt (100%) rename {code => exercises}/asan/Makefile (100%) rename {code => exercises}/asan/README.md (100%) rename {code => exercises}/asan/asan.cpp (100%) rename {code => exercises}/asan/solution/asan.sol.cpp (100%) rename {code => exercises}/atomic/CMakeLists.txt (100%) rename {code => exercises}/atomic/Makefile (100%) rename {code => exercises}/atomic/README.md (100%) rename {code => exercises}/atomic/atomic.cpp (100%) rename {code => exercises}/atomic/solution/atomic.sol.cpp (100%) rename {code => exercises}/callgrind/CMakeLists.txt (100%) rename {code => exercises}/callgrind/Makefile (100%) rename {code => exercises}/callgrind/README.md (100%) rename {code => exercises}/callgrind/fibocrunch.cpp (100%) rename {code => exercises}/callgrind/solution/fibocrunch.sol.cpp (100%) rename {code => exercises}/check_setup.sh (100%) rename {code => exercises/code}/memcheck/README.md (100%) rename {code => exercises}/common.cmake (100%) rename {code => exercises}/concepts/CMakeLists.txt (100%) rename {code => exercises}/concepts/Makefile (100%) rename {code => exercises}/concepts/README.md (100%) rename {code => exercises}/concepts/concepts.cpp (100%) rename {code => exercises}/concepts/solution/concepts.sol1.cpp (100%) rename {code => exercises}/concepts/solution/concepts.sol2.cpp (100%) rename {code => exercises}/condition_variable/CMakeLists.txt (100%) rename {code => exercises}/condition_variable/Makefile (100%) rename {code => exercises}/condition_variable/condition_variable.cpp (100%) rename {code => exercises}/condition_variable/solution/condition_variable.sol.cpp (100%) rename {code => exercises}/constness/CMakeLists.txt (100%) rename {code => exercises}/constness/Makefile (100%) rename {code => exercises}/constness/README.md (100%) rename {code => exercises}/constness/constplay.cpp (100%) rename {code => exercises}/control/CMakeLists.txt (100%) rename {code => exercises}/control/Makefile (100%) rename {code => exercises}/control/README.md (100%) rename {code => exercises}/control/control.cpp (100%) rename {code => exercises}/control/solution/control.sol.cpp (100%) rename {code => exercises}/cppcheck/CMakeLists.txt (100%) rename {code => exercises}/cppcheck/Makefile (100%) rename {code => exercises}/cppcheck/README.md (100%) rename {code => exercises}/cppcheck/randomize.cpp (100%) rename {code => exercises}/cppcheck/solution/randomize.sol.cpp (100%) rename {code => exercises}/debug/CMakeLists.txt (100%) rename {code => exercises}/debug/Makefile (100%) rename {code => exercises}/debug/README.md (100%) rename {code => exercises}/debug/debug.cpp (100%) rename {code => exercises}/debug/solution/debug.sol.cpp (100%) rename {code => exercises}/functions/CMakeLists.txt (100%) rename {code => exercises}/functions/Makefile (100%) rename {code => exercises}/functions/README.md (100%) rename {code => exercises}/functions/Structs.cpp (100%) rename {code => exercises}/functions/Structs.h (100%) rename {code => exercises}/functions/functions.cpp (100%) rename {code => exercises}/functions/solution/functions.sol.cpp (100%) rename {code => exercises}/header_units/Complex.hpp (100%) rename {code => exercises}/header_units/Makefile (100%) rename {code => exercises}/header_units/README.md (100%) rename {code => exercises}/header_units/main.cpp (100%) rename {code => exercises}/header_units/solution/Makefile (100%) rename {code => exercises}/header_units/solution/main.cpp (100%) rename {code => exercises}/helgrind/CMakeLists.txt (100%) rename {code => exercises}/helgrind/Makefile (100%) rename {code => exercises}/helgrind/README.md (100%) rename {code => exercises}/helgrind/fiboMT.cpp (100%) rename {code => exercises}/helgrind/solution/fiboMT.sol.cpp (100%) rename {code => exercises}/hello/CMakeLists.txt (100%) rename {code => exercises}/hello/Makefile (100%) rename {code => exercises}/hello/README.md (100%) rename {code => exercises}/hello/hello.cpp (100%) rename {code => exercises}/hello/hello.hpp (100%) rename {code => exercises}/hello/main.cpp (100%) rename {code => exercises}/loopsRefsAuto/CMakeLists.txt (100%) rename {code => exercises}/loopsRefsAuto/Makefile (100%) rename {code => exercises}/loopsRefsAuto/README.md (100%) rename {code => exercises}/loopsRefsAuto/loopsRefsAuto.cpp (100%) rename {code => exercises}/loopsRefsAuto/solution/loopsRefsAuto.sol.cpp (100%) rename {code => exercises}/memcheck/CMakeLists.txt (100%) rename {code => exercises}/memcheck/Makefile (100%) rename {code => exercises}/memcheck/Polygons.cpp (100%) rename {code => exercises}/memcheck/Polygons.hpp (100%) create mode 100644 exercises/memcheck/README.md rename {code => exercises}/memcheck/memleak.cpp (100%) rename {code => exercises}/memcheck/solution/Polygons.sol.cpp (100%) rename {code => exercises}/memcheck/solution/Polygons.sol.hpp (100%) rename {code => exercises}/memcheck/solution/memleak.sol.cpp (100%) rename {code => exercises}/modern_oo/CMakeLists.txt (100%) rename {code => exercises}/modern_oo/Makefile (100%) rename {code => exercises}/modern_oo/README.md (100%) rename {code => exercises}/modern_oo/particles.cpp (100%) rename {code => exercises}/modern_oo/solution/particles.sol.cpp (100%) rename {code => exercises}/modules/Complex.hpp (100%) rename {code => exercises}/modules/Makefile (100%) rename {code => exercises}/modules/README.md (100%) rename {code => exercises}/modules/main.cpp (100%) rename {code => exercises}/modules/solution/Complex.cpp (100%) rename {code => exercises}/modules/solution/Makefile (100%) rename {code => exercises}/modules/solution/main.cpp (100%) rename {code => exercises}/move/CMakeLists.txt (100%) rename {code => exercises}/move/Makefile (100%) rename {code => exercises}/move/README.md (100%) rename {code => exercises}/move/solution/trymove.sol.cpp (100%) rename {code => exercises}/move/trymove.cpp (100%) rename {code => exercises}/operators/CMakeLists.txt (100%) rename {code => exercises}/operators/Makefile (100%) rename {code => exercises}/operators/README.md (100%) rename {code => exercises}/operators/operators.cpp (100%) rename {code => exercises}/operators/solution/operators.sol.cpp (100%) rename {code => exercises}/optional/CMakeLists.txt (100%) rename {code => exercises}/optional/Makefile (100%) rename {code => exercises}/optional/README.md (100%) rename {code => exercises}/optional/optional.cpp (100%) rename {code => exercises}/optional/solution/optional.sol.cpp (100%) rename {code => exercises}/polymorphism/CMakeLists.txt (100%) rename {code => exercises}/polymorphism/Makefile (100%) rename {code => exercises}/polymorphism/Polygons.cpp (100%) rename {code => exercises}/polymorphism/Polygons.hpp (100%) rename {code => exercises}/polymorphism/README.md (100%) rename {code => exercises}/polymorphism/solution/trypoly.sol.cpp (100%) rename {code => exercises}/polymorphism/trypoly.cpp (100%) rename {code => exercises}/python/CMakeLists.txt (100%) rename {code => exercises}/python/Complex.hpp (100%) rename {code => exercises}/python/Makefile (100%) rename {code => exercises}/python/README.md (100%) rename {code => exercises}/python/mandel.cpp (100%) rename {code => exercises}/python/mandel.hpp (100%) rename {code => exercises}/python/mandel.py (100%) rename {code => exercises}/python/mandel_cwrapper.cpp (100%) rename {code => exercises}/python/mandel_cwrapper.hpp (100%) rename {code => exercises}/python/mandel_module.cpp (100%) rename {code => exercises}/python/solution/mandel.sol.py (100%) rename {code => exercises}/python/solution/mandel.solctype.py (100%) rename {code => exercises}/race/CMakeLists.txt (100%) rename {code => exercises}/race/Makefile (100%) rename {code => exercises}/race/README.md (100%) rename {code => exercises}/race/racing.cpp (100%) rename {code => exercises}/race/run (100%) rename {code => exercises}/race/solution/racing.sol.cpp (100%) rename {code => exercises}/smartPointers/CMakeLists.txt (100%) rename {code => exercises}/smartPointers/Makefile (100%) rename {code => exercises}/smartPointers/README.md (100%) rename {code => exercises}/smartPointers/smartPointers.cpp (100%) rename {code => exercises}/smartPointers/solution/smartPointers.sol.cpp (100%) rename {code => exercises}/spaceship/CMakeLists.txt (100%) rename {code => exercises}/spaceship/Makefile (100%) rename {code => exercises}/spaceship/README.md (100%) rename {code => exercises}/spaceship/solution/spaceship.sol.cpp (100%) rename {code => exercises}/spaceship/spaceship.cpp (100%) rename {code => exercises}/stl/CMakeLists.txt (100%) rename {code => exercises}/stl/Complex.hpp (100%) rename {code => exercises}/stl/Makefile (100%) rename {code => exercises}/stl/README.md (100%) rename {code => exercises}/stl/randomize.cpp (100%) rename {code => exercises}/stl/randomize.nostl.cpp (100%) rename {code => exercises}/stl/solution/randomize.sol.cpp (100%) rename {code => exercises}/templates/CMakeLists.txt (100%) rename {code => exercises}/templates/Complex.hpp (100%) rename {code => exercises}/templates/Makefile (100%) rename {code => exercises}/templates/OrderedVector.hpp (100%) rename {code => exercises}/templates/README.md (100%) rename {code => exercises}/templates/playwithsort.cpp (100%) rename {code => exercises}/templates/solution/OrderedVector.sol.hpp (100%) rename {code => exercises}/templates/solution/playwithsort.sol.cpp (100%) rename {code => exercises}/valgrind/CMakeLists.txt (100%) rename {code => exercises}/valgrind/Makefile (100%) rename {code => exercises}/valgrind/README.md (100%) rename {code => exercises}/valgrind/debug.cpp (100%) rename {code => exercises}/valgrind/solution/debug.sol.cpp (100%) rename {code => exercises}/variadic/CMakeLists.txt (100%) rename {code => exercises}/variadic/Makefile (100%) rename {code => exercises}/variadic/README.md (100%) rename {code => exercises}/variadic/solution/variadic.sol.cpp (100%) rename {code => exercises}/variadic/variadic.cpp (100%) rename {code => exercises}/variant/CMakeLists.txt (100%) rename {code => exercises}/variant/Makefile (100%) rename {code => exercises}/variant/README.md (100%) rename {code => exercises}/variant/solution/variant.sol1.cpp (100%) rename {code => exercises}/variant/solution/variant.sol2.cpp (100%) rename {code => exercises}/variant/variant.cpp (100%) rename {code => exercises}/virtual_inheritance/CMakeLists.txt (100%) rename {code => exercises}/virtual_inheritance/Makefile (100%) rename {code => exercises}/virtual_inheritance/README.md (100%) rename {code => exercises}/virtual_inheritance/TextBox.cpp (100%) rename {code => exercises}/virtual_inheritance/TextBox.hpp (100%) rename {code => exercises}/virtual_inheritance/solution/TextBox.cpp (100%) rename {code => exercises}/virtual_inheritance/solution/TextBox.hpp (100%) rename {code => exercises}/virtual_inheritance/solution/trymultiherit.sol.cpp (100%) rename {code => exercises}/virtual_inheritance/trymultiherit.cpp (100%) diff --git a/.github/workflows/build-exercises.yml b/.github/workflows/build-exercises.yml index 5c8d51a5..87127501 100644 --- a/.github/workflows/build-exercises.yml +++ b/.github/workflows/build-exercises.yml @@ -2,10 +2,10 @@ name: Build exercises on: push: paths: - - 'code/**' + - 'exercises/**' pull_request: paths: - - 'code/**' + - 'exercises/**' - '.github/workflows/**' # Cancel running jobs on force-push @@ -100,7 +100,7 @@ jobs: - uses: actions/checkout@v3 # Run the CMake configuration. - name: CMake Configure - run: cmake -S ${{ github.workspace }}/code/${{ matrix.EXERCISE.NAME }} + run: cmake -S ${{ github.workspace }}/exercises/${{ matrix.EXERCISE.NAME }} -B build ${{ matrix.PLATFORM.GENERATOR }} # Perform the build of the "main exercise" with CMake. @@ -113,12 +113,12 @@ jobs: if: ${{ !matrix.EXERCISE.SKIP_SOLUTION || false }} # Perform the build of the "main exercise" with GNU Make. - name: GNU Make Build Main - run: make -C ${{ github.workspace }}/code/${{ matrix.EXERCISE.NAME }} + run: make -C ${{ github.workspace }}/exercises/${{ matrix.EXERCISE.NAME }} if: ${{ matrix.PLATFORM.OS != 'windows-latest' && (!matrix.EXERCISE.SKIP_DEFAULT || false) }} # Perform the build of the "solution" with GNU Make. - name: GNU Make Build Solution - run: make -C ${{ github.workspace }}/code/${{ matrix.EXERCISE.NAME }} + run: make -C ${{ github.workspace }}/exercises/${{ matrix.EXERCISE.NAME }} solution if: ${{ matrix.PLATFORM.OS != 'windows-latest' && (!matrix.EXERCISE.SKIP_SOLUTION || false) }} diff --git a/.gitignore b/.gitignore index ec42d46e..d69a7982 100644 --- a/.gitignore +++ b/.gitignore @@ -19,30 +19,30 @@ build *.so *.sol *.sol? -code/*aux -code/callgrind/fibocrunch -code/control/control -code/loopsRefsAuto/loopsRefsAuto -code/operators/operators -code/concepts/concepts -code/constness/constplay -code/cppcheck/randomize -code/debug/randomize -code/functions/functions -code/helgrind/fiboMT -code/hello/hello -code/lambdas/randomize -code/memcheck/memleak -code/move/trymove -code/optional/optional -code/polymorphism/trypoly -code/race/racing -code/stl/randomize.nostl -code/templates/playwithsort -code/valgrind/randomize -code/variant/variant -code/virtual_inheritance/trymultiherit -code/smartPointers/smartPointers +exercises/*aux +exercises/callgrind/fibocrunch +exercises/control/control +exercises/loopsRefsAuto/loopsRefsAuto +exercises/operators/operators +exercises/concepts/concepts +exercises/constness/constplay +exercises/cppcheck/randomize +exercises/debug/randomize +exercises/functions/functions +exercises/helgrind/fiboMT +exercises/hello/hello +exercises/lambdas/randomize +exercises/memcheck/memleak +exercises/move/trymove +exercises/optional/optional +exercises/polymorphism/trypoly +exercises/race/racing +exercises/stl/randomize.nostl +exercises/templates/playwithsort +exercises/valgrind/randomize +exercises/variant/variant +exercises/virtual_inheritance/trymultiherit +exercises/smartPointers/smartPointers # tools CMakeCache.txt diff --git a/README.md b/README.md index 0128e2b9..82409239 100644 --- a/README.md +++ b/README.md @@ -87,8 +87,8 @@ make solution ### For Mentors -Depending on which course is running, consult the schedule for exercise sessions in [essentials](code/ExerciseSchedule_EssentialCourse.md) or [advanced](code/ExerciseSchedule_AdvancedCourse.md). -For mentors, there is a [cheat sheet](code/ExercisesCheatSheet.md) with hints towards the solutions and key points to discuss during the exercise sessions. +Depending on which course is running, consult the schedule for exercise sessions in [essentials](exercises/ExerciseSchedule_EssentialCourse.md) or [advanced](exercises/ExerciseSchedule_AdvancedCourse.md). +For mentors, there is a [cheat sheet](exercises/ExercisesCheatSheet.md) with hints towards the solutions and key points to discuss during the exercise sessions. ## Contributors ✨ diff --git a/code/.clang-format b/exercises/.clang-format similarity index 100% rename from code/.clang-format rename to exercises/.clang-format diff --git a/code/CMakeLists.txt b/exercises/CMakeLists.txt similarity index 100% rename from code/CMakeLists.txt rename to exercises/CMakeLists.txt diff --git a/code/ExerciseSchedule_AdvancedCourse.md b/exercises/ExerciseSchedule_AdvancedCourse.md similarity index 100% rename from code/ExerciseSchedule_AdvancedCourse.md rename to exercises/ExerciseSchedule_AdvancedCourse.md diff --git a/code/ExerciseSchedule_EssentialCourse.md b/exercises/ExerciseSchedule_EssentialCourse.md similarity index 100% rename from code/ExerciseSchedule_EssentialCourse.md rename to exercises/ExerciseSchedule_EssentialCourse.md diff --git a/code/ExercisesCheatSheet.md b/exercises/ExercisesCheatSheet.md similarity index 99% rename from code/ExercisesCheatSheet.md rename to exercises/ExercisesCheatSheet.md index a00cee71..42f3ad4c 100644 --- a/code/ExercisesCheatSheet.md +++ b/exercises/ExercisesCheatSheet.md @@ -247,7 +247,7 @@ Steps: 3. Inspect changes, try `git diff .` 4. Revert changes using `git checkout -- ` or `git checkout .` 5. You can repeat this with various other styles if you want. Supported are: LLVM, Google, Chromium, Mozilla, WebKit, Microsoft. -6. Go to `code` directory and create a `.clang-format` file: +6. Go to `exercises` directory and create a `.clang-format` file: `clang-format -style=LLVM -dump-config > .clang-format`. Have a look at the file. You can also show this webpage so students can get an idea of what's possible: https://clang.llvm.org/docs/ClangFormatStyleOptions.html diff --git a/code/Makefile b/exercises/Makefile similarity index 100% rename from code/Makefile rename to exercises/Makefile diff --git a/code/README.md b/exercises/README.md similarity index 97% rename from code/README.md rename to exercises/README.md index b60706e4..160793fe 100644 --- a/code/README.md +++ b/exercises/README.md @@ -14,7 +14,7 @@ Getting the code ```bash git clone https://github.com/hsf-training/cpluspluscourse.git -cd cpluspluscourse/code +cd cpluspluscourse/exercises ``` Recommended setup @@ -57,13 +57,13 @@ How to test your setup ---------------------- - **Please run [`check_setup.sh`](check_setup.sh) to check your setup on Linux / Mac.** The optional tools are not required for the essentials course. - - go to [`code/hello`](hello) + - go to [`exercises/hello`](hello) - follow the `README.md` ### How to compile and run? ```bash -cd code/hello +cd exercises/hello make export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:. ./hello @@ -83,7 +83,7 @@ Each exercise is in a subdirectory with mainly 4 sets of files ### Instructions - Each exercise comes with a set of instructions in the course slides - - Most of them also with a `README.md` in the exercise subdir + - Most of them also with a `README.md` in the `exercises` subdir - And with instructions in the code ### *.hpp and *.cpp files @@ -120,7 +120,7 @@ Using lxplus ssh lxplus9.cern.ch export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:. git clone https://github.com/hsf-training/cpluspluscourse.git -cd cpluspluscourse/code/hello +cd cpluspluscourse/exercises/hello make ./hello ``` @@ -253,7 +253,7 @@ There are two ways to launch VS Code for working with WSL: Use the newly opened terminal to type commands for building, debugging, etc. 2. Terminal first: Launch `bash` or `wsl` either via a powershell or from Windows Terminal (if installed). Navigate to your cloned GitHub repository, or `git clone` it if you have not done it yet. - Inside the `/code` or any `/code/example` directory, run `code .`. + Inside the `/exercises` or any `/exercises/example` directory, run `code .`. This will launch VS Code on Windows, already connected to your WSL and set to the right folder. Use your initial terminal to type commands for building, debugging etc. diff --git a/code/asan/CMakeLists.txt b/exercises/asan/CMakeLists.txt similarity index 100% rename from code/asan/CMakeLists.txt rename to exercises/asan/CMakeLists.txt diff --git a/code/asan/Makefile b/exercises/asan/Makefile similarity index 100% rename from code/asan/Makefile rename to exercises/asan/Makefile diff --git a/code/asan/README.md b/exercises/asan/README.md similarity index 100% rename from code/asan/README.md rename to exercises/asan/README.md diff --git a/code/asan/asan.cpp b/exercises/asan/asan.cpp similarity index 100% rename from code/asan/asan.cpp rename to exercises/asan/asan.cpp diff --git a/code/asan/solution/asan.sol.cpp b/exercises/asan/solution/asan.sol.cpp similarity index 100% rename from code/asan/solution/asan.sol.cpp rename to exercises/asan/solution/asan.sol.cpp diff --git a/code/atomic/CMakeLists.txt b/exercises/atomic/CMakeLists.txt similarity index 100% rename from code/atomic/CMakeLists.txt rename to exercises/atomic/CMakeLists.txt diff --git a/code/atomic/Makefile b/exercises/atomic/Makefile similarity index 100% rename from code/atomic/Makefile rename to exercises/atomic/Makefile diff --git a/code/atomic/README.md b/exercises/atomic/README.md similarity index 100% rename from code/atomic/README.md rename to exercises/atomic/README.md diff --git a/code/atomic/atomic.cpp b/exercises/atomic/atomic.cpp similarity index 100% rename from code/atomic/atomic.cpp rename to exercises/atomic/atomic.cpp diff --git a/code/atomic/solution/atomic.sol.cpp b/exercises/atomic/solution/atomic.sol.cpp similarity index 100% rename from code/atomic/solution/atomic.sol.cpp rename to exercises/atomic/solution/atomic.sol.cpp diff --git a/code/callgrind/CMakeLists.txt b/exercises/callgrind/CMakeLists.txt similarity index 100% rename from code/callgrind/CMakeLists.txt rename to exercises/callgrind/CMakeLists.txt diff --git a/code/callgrind/Makefile b/exercises/callgrind/Makefile similarity index 100% rename from code/callgrind/Makefile rename to exercises/callgrind/Makefile diff --git a/code/callgrind/README.md b/exercises/callgrind/README.md similarity index 100% rename from code/callgrind/README.md rename to exercises/callgrind/README.md diff --git a/code/callgrind/fibocrunch.cpp b/exercises/callgrind/fibocrunch.cpp similarity index 100% rename from code/callgrind/fibocrunch.cpp rename to exercises/callgrind/fibocrunch.cpp diff --git a/code/callgrind/solution/fibocrunch.sol.cpp b/exercises/callgrind/solution/fibocrunch.sol.cpp similarity index 100% rename from code/callgrind/solution/fibocrunch.sol.cpp rename to exercises/callgrind/solution/fibocrunch.sol.cpp diff --git a/code/check_setup.sh b/exercises/check_setup.sh similarity index 100% rename from code/check_setup.sh rename to exercises/check_setup.sh diff --git a/code/memcheck/README.md b/exercises/code/memcheck/README.md similarity index 100% rename from code/memcheck/README.md rename to exercises/code/memcheck/README.md diff --git a/code/common.cmake b/exercises/common.cmake similarity index 100% rename from code/common.cmake rename to exercises/common.cmake diff --git a/code/concepts/CMakeLists.txt b/exercises/concepts/CMakeLists.txt similarity index 100% rename from code/concepts/CMakeLists.txt rename to exercises/concepts/CMakeLists.txt diff --git a/code/concepts/Makefile b/exercises/concepts/Makefile similarity index 100% rename from code/concepts/Makefile rename to exercises/concepts/Makefile diff --git a/code/concepts/README.md b/exercises/concepts/README.md similarity index 100% rename from code/concepts/README.md rename to exercises/concepts/README.md diff --git a/code/concepts/concepts.cpp b/exercises/concepts/concepts.cpp similarity index 100% rename from code/concepts/concepts.cpp rename to exercises/concepts/concepts.cpp diff --git a/code/concepts/solution/concepts.sol1.cpp b/exercises/concepts/solution/concepts.sol1.cpp similarity index 100% rename from code/concepts/solution/concepts.sol1.cpp rename to exercises/concepts/solution/concepts.sol1.cpp diff --git a/code/concepts/solution/concepts.sol2.cpp b/exercises/concepts/solution/concepts.sol2.cpp similarity index 100% rename from code/concepts/solution/concepts.sol2.cpp rename to exercises/concepts/solution/concepts.sol2.cpp diff --git a/code/condition_variable/CMakeLists.txt b/exercises/condition_variable/CMakeLists.txt similarity index 100% rename from code/condition_variable/CMakeLists.txt rename to exercises/condition_variable/CMakeLists.txt diff --git a/code/condition_variable/Makefile b/exercises/condition_variable/Makefile similarity index 100% rename from code/condition_variable/Makefile rename to exercises/condition_variable/Makefile diff --git a/code/condition_variable/condition_variable.cpp b/exercises/condition_variable/condition_variable.cpp similarity index 100% rename from code/condition_variable/condition_variable.cpp rename to exercises/condition_variable/condition_variable.cpp diff --git a/code/condition_variable/solution/condition_variable.sol.cpp b/exercises/condition_variable/solution/condition_variable.sol.cpp similarity index 100% rename from code/condition_variable/solution/condition_variable.sol.cpp rename to exercises/condition_variable/solution/condition_variable.sol.cpp diff --git a/code/constness/CMakeLists.txt b/exercises/constness/CMakeLists.txt similarity index 100% rename from code/constness/CMakeLists.txt rename to exercises/constness/CMakeLists.txt diff --git a/code/constness/Makefile b/exercises/constness/Makefile similarity index 100% rename from code/constness/Makefile rename to exercises/constness/Makefile diff --git a/code/constness/README.md b/exercises/constness/README.md similarity index 100% rename from code/constness/README.md rename to exercises/constness/README.md diff --git a/code/constness/constplay.cpp b/exercises/constness/constplay.cpp similarity index 100% rename from code/constness/constplay.cpp rename to exercises/constness/constplay.cpp diff --git a/code/control/CMakeLists.txt b/exercises/control/CMakeLists.txt similarity index 100% rename from code/control/CMakeLists.txt rename to exercises/control/CMakeLists.txt diff --git a/code/control/Makefile b/exercises/control/Makefile similarity index 100% rename from code/control/Makefile rename to exercises/control/Makefile diff --git a/code/control/README.md b/exercises/control/README.md similarity index 100% rename from code/control/README.md rename to exercises/control/README.md diff --git a/code/control/control.cpp b/exercises/control/control.cpp similarity index 100% rename from code/control/control.cpp rename to exercises/control/control.cpp diff --git a/code/control/solution/control.sol.cpp b/exercises/control/solution/control.sol.cpp similarity index 100% rename from code/control/solution/control.sol.cpp rename to exercises/control/solution/control.sol.cpp diff --git a/code/cppcheck/CMakeLists.txt b/exercises/cppcheck/CMakeLists.txt similarity index 100% rename from code/cppcheck/CMakeLists.txt rename to exercises/cppcheck/CMakeLists.txt diff --git a/code/cppcheck/Makefile b/exercises/cppcheck/Makefile similarity index 100% rename from code/cppcheck/Makefile rename to exercises/cppcheck/Makefile diff --git a/code/cppcheck/README.md b/exercises/cppcheck/README.md similarity index 100% rename from code/cppcheck/README.md rename to exercises/cppcheck/README.md diff --git a/code/cppcheck/randomize.cpp b/exercises/cppcheck/randomize.cpp similarity index 100% rename from code/cppcheck/randomize.cpp rename to exercises/cppcheck/randomize.cpp diff --git a/code/cppcheck/solution/randomize.sol.cpp b/exercises/cppcheck/solution/randomize.sol.cpp similarity index 100% rename from code/cppcheck/solution/randomize.sol.cpp rename to exercises/cppcheck/solution/randomize.sol.cpp diff --git a/code/debug/CMakeLists.txt b/exercises/debug/CMakeLists.txt similarity index 100% rename from code/debug/CMakeLists.txt rename to exercises/debug/CMakeLists.txt diff --git a/code/debug/Makefile b/exercises/debug/Makefile similarity index 100% rename from code/debug/Makefile rename to exercises/debug/Makefile diff --git a/code/debug/README.md b/exercises/debug/README.md similarity index 100% rename from code/debug/README.md rename to exercises/debug/README.md diff --git a/code/debug/debug.cpp b/exercises/debug/debug.cpp similarity index 100% rename from code/debug/debug.cpp rename to exercises/debug/debug.cpp diff --git a/code/debug/solution/debug.sol.cpp b/exercises/debug/solution/debug.sol.cpp similarity index 100% rename from code/debug/solution/debug.sol.cpp rename to exercises/debug/solution/debug.sol.cpp diff --git a/code/functions/CMakeLists.txt b/exercises/functions/CMakeLists.txt similarity index 100% rename from code/functions/CMakeLists.txt rename to exercises/functions/CMakeLists.txt diff --git a/code/functions/Makefile b/exercises/functions/Makefile similarity index 100% rename from code/functions/Makefile rename to exercises/functions/Makefile diff --git a/code/functions/README.md b/exercises/functions/README.md similarity index 100% rename from code/functions/README.md rename to exercises/functions/README.md diff --git a/code/functions/Structs.cpp b/exercises/functions/Structs.cpp similarity index 100% rename from code/functions/Structs.cpp rename to exercises/functions/Structs.cpp diff --git a/code/functions/Structs.h b/exercises/functions/Structs.h similarity index 100% rename from code/functions/Structs.h rename to exercises/functions/Structs.h diff --git a/code/functions/functions.cpp b/exercises/functions/functions.cpp similarity index 100% rename from code/functions/functions.cpp rename to exercises/functions/functions.cpp diff --git a/code/functions/solution/functions.sol.cpp b/exercises/functions/solution/functions.sol.cpp similarity index 100% rename from code/functions/solution/functions.sol.cpp rename to exercises/functions/solution/functions.sol.cpp diff --git a/code/header_units/Complex.hpp b/exercises/header_units/Complex.hpp similarity index 100% rename from code/header_units/Complex.hpp rename to exercises/header_units/Complex.hpp diff --git a/code/header_units/Makefile b/exercises/header_units/Makefile similarity index 100% rename from code/header_units/Makefile rename to exercises/header_units/Makefile diff --git a/code/header_units/README.md b/exercises/header_units/README.md similarity index 100% rename from code/header_units/README.md rename to exercises/header_units/README.md diff --git a/code/header_units/main.cpp b/exercises/header_units/main.cpp similarity index 100% rename from code/header_units/main.cpp rename to exercises/header_units/main.cpp diff --git a/code/header_units/solution/Makefile b/exercises/header_units/solution/Makefile similarity index 100% rename from code/header_units/solution/Makefile rename to exercises/header_units/solution/Makefile diff --git a/code/header_units/solution/main.cpp b/exercises/header_units/solution/main.cpp similarity index 100% rename from code/header_units/solution/main.cpp rename to exercises/header_units/solution/main.cpp diff --git a/code/helgrind/CMakeLists.txt b/exercises/helgrind/CMakeLists.txt similarity index 100% rename from code/helgrind/CMakeLists.txt rename to exercises/helgrind/CMakeLists.txt diff --git a/code/helgrind/Makefile b/exercises/helgrind/Makefile similarity index 100% rename from code/helgrind/Makefile rename to exercises/helgrind/Makefile diff --git a/code/helgrind/README.md b/exercises/helgrind/README.md similarity index 100% rename from code/helgrind/README.md rename to exercises/helgrind/README.md diff --git a/code/helgrind/fiboMT.cpp b/exercises/helgrind/fiboMT.cpp similarity index 100% rename from code/helgrind/fiboMT.cpp rename to exercises/helgrind/fiboMT.cpp diff --git a/code/helgrind/solution/fiboMT.sol.cpp b/exercises/helgrind/solution/fiboMT.sol.cpp similarity index 100% rename from code/helgrind/solution/fiboMT.sol.cpp rename to exercises/helgrind/solution/fiboMT.sol.cpp diff --git a/code/hello/CMakeLists.txt b/exercises/hello/CMakeLists.txt similarity index 100% rename from code/hello/CMakeLists.txt rename to exercises/hello/CMakeLists.txt diff --git a/code/hello/Makefile b/exercises/hello/Makefile similarity index 100% rename from code/hello/Makefile rename to exercises/hello/Makefile diff --git a/code/hello/README.md b/exercises/hello/README.md similarity index 100% rename from code/hello/README.md rename to exercises/hello/README.md diff --git a/code/hello/hello.cpp b/exercises/hello/hello.cpp similarity index 100% rename from code/hello/hello.cpp rename to exercises/hello/hello.cpp diff --git a/code/hello/hello.hpp b/exercises/hello/hello.hpp similarity index 100% rename from code/hello/hello.hpp rename to exercises/hello/hello.hpp diff --git a/code/hello/main.cpp b/exercises/hello/main.cpp similarity index 100% rename from code/hello/main.cpp rename to exercises/hello/main.cpp diff --git a/code/loopsRefsAuto/CMakeLists.txt b/exercises/loopsRefsAuto/CMakeLists.txt similarity index 100% rename from code/loopsRefsAuto/CMakeLists.txt rename to exercises/loopsRefsAuto/CMakeLists.txt diff --git a/code/loopsRefsAuto/Makefile b/exercises/loopsRefsAuto/Makefile similarity index 100% rename from code/loopsRefsAuto/Makefile rename to exercises/loopsRefsAuto/Makefile diff --git a/code/loopsRefsAuto/README.md b/exercises/loopsRefsAuto/README.md similarity index 100% rename from code/loopsRefsAuto/README.md rename to exercises/loopsRefsAuto/README.md diff --git a/code/loopsRefsAuto/loopsRefsAuto.cpp b/exercises/loopsRefsAuto/loopsRefsAuto.cpp similarity index 100% rename from code/loopsRefsAuto/loopsRefsAuto.cpp rename to exercises/loopsRefsAuto/loopsRefsAuto.cpp diff --git a/code/loopsRefsAuto/solution/loopsRefsAuto.sol.cpp b/exercises/loopsRefsAuto/solution/loopsRefsAuto.sol.cpp similarity index 100% rename from code/loopsRefsAuto/solution/loopsRefsAuto.sol.cpp rename to exercises/loopsRefsAuto/solution/loopsRefsAuto.sol.cpp diff --git a/code/memcheck/CMakeLists.txt b/exercises/memcheck/CMakeLists.txt similarity index 100% rename from code/memcheck/CMakeLists.txt rename to exercises/memcheck/CMakeLists.txt diff --git a/code/memcheck/Makefile b/exercises/memcheck/Makefile similarity index 100% rename from code/memcheck/Makefile rename to exercises/memcheck/Makefile diff --git a/code/memcheck/Polygons.cpp b/exercises/memcheck/Polygons.cpp similarity index 100% rename from code/memcheck/Polygons.cpp rename to exercises/memcheck/Polygons.cpp diff --git a/code/memcheck/Polygons.hpp b/exercises/memcheck/Polygons.hpp similarity index 100% rename from code/memcheck/Polygons.hpp rename to exercises/memcheck/Polygons.hpp diff --git a/exercises/memcheck/README.md b/exercises/memcheck/README.md new file mode 100644 index 00000000..e69de29b diff --git a/code/memcheck/memleak.cpp b/exercises/memcheck/memleak.cpp similarity index 100% rename from code/memcheck/memleak.cpp rename to exercises/memcheck/memleak.cpp diff --git a/code/memcheck/solution/Polygons.sol.cpp b/exercises/memcheck/solution/Polygons.sol.cpp similarity index 100% rename from code/memcheck/solution/Polygons.sol.cpp rename to exercises/memcheck/solution/Polygons.sol.cpp diff --git a/code/memcheck/solution/Polygons.sol.hpp b/exercises/memcheck/solution/Polygons.sol.hpp similarity index 100% rename from code/memcheck/solution/Polygons.sol.hpp rename to exercises/memcheck/solution/Polygons.sol.hpp diff --git a/code/memcheck/solution/memleak.sol.cpp b/exercises/memcheck/solution/memleak.sol.cpp similarity index 100% rename from code/memcheck/solution/memleak.sol.cpp rename to exercises/memcheck/solution/memleak.sol.cpp diff --git a/code/modern_oo/CMakeLists.txt b/exercises/modern_oo/CMakeLists.txt similarity index 100% rename from code/modern_oo/CMakeLists.txt rename to exercises/modern_oo/CMakeLists.txt diff --git a/code/modern_oo/Makefile b/exercises/modern_oo/Makefile similarity index 100% rename from code/modern_oo/Makefile rename to exercises/modern_oo/Makefile diff --git a/code/modern_oo/README.md b/exercises/modern_oo/README.md similarity index 100% rename from code/modern_oo/README.md rename to exercises/modern_oo/README.md diff --git a/code/modern_oo/particles.cpp b/exercises/modern_oo/particles.cpp similarity index 100% rename from code/modern_oo/particles.cpp rename to exercises/modern_oo/particles.cpp diff --git a/code/modern_oo/solution/particles.sol.cpp b/exercises/modern_oo/solution/particles.sol.cpp similarity index 100% rename from code/modern_oo/solution/particles.sol.cpp rename to exercises/modern_oo/solution/particles.sol.cpp diff --git a/code/modules/Complex.hpp b/exercises/modules/Complex.hpp similarity index 100% rename from code/modules/Complex.hpp rename to exercises/modules/Complex.hpp diff --git a/code/modules/Makefile b/exercises/modules/Makefile similarity index 100% rename from code/modules/Makefile rename to exercises/modules/Makefile diff --git a/code/modules/README.md b/exercises/modules/README.md similarity index 100% rename from code/modules/README.md rename to exercises/modules/README.md diff --git a/code/modules/main.cpp b/exercises/modules/main.cpp similarity index 100% rename from code/modules/main.cpp rename to exercises/modules/main.cpp diff --git a/code/modules/solution/Complex.cpp b/exercises/modules/solution/Complex.cpp similarity index 100% rename from code/modules/solution/Complex.cpp rename to exercises/modules/solution/Complex.cpp diff --git a/code/modules/solution/Makefile b/exercises/modules/solution/Makefile similarity index 100% rename from code/modules/solution/Makefile rename to exercises/modules/solution/Makefile diff --git a/code/modules/solution/main.cpp b/exercises/modules/solution/main.cpp similarity index 100% rename from code/modules/solution/main.cpp rename to exercises/modules/solution/main.cpp diff --git a/code/move/CMakeLists.txt b/exercises/move/CMakeLists.txt similarity index 100% rename from code/move/CMakeLists.txt rename to exercises/move/CMakeLists.txt diff --git a/code/move/Makefile b/exercises/move/Makefile similarity index 100% rename from code/move/Makefile rename to exercises/move/Makefile diff --git a/code/move/README.md b/exercises/move/README.md similarity index 100% rename from code/move/README.md rename to exercises/move/README.md diff --git a/code/move/solution/trymove.sol.cpp b/exercises/move/solution/trymove.sol.cpp similarity index 100% rename from code/move/solution/trymove.sol.cpp rename to exercises/move/solution/trymove.sol.cpp diff --git a/code/move/trymove.cpp b/exercises/move/trymove.cpp similarity index 100% rename from code/move/trymove.cpp rename to exercises/move/trymove.cpp diff --git a/code/operators/CMakeLists.txt b/exercises/operators/CMakeLists.txt similarity index 100% rename from code/operators/CMakeLists.txt rename to exercises/operators/CMakeLists.txt diff --git a/code/operators/Makefile b/exercises/operators/Makefile similarity index 100% rename from code/operators/Makefile rename to exercises/operators/Makefile diff --git a/code/operators/README.md b/exercises/operators/README.md similarity index 100% rename from code/operators/README.md rename to exercises/operators/README.md diff --git a/code/operators/operators.cpp b/exercises/operators/operators.cpp similarity index 100% rename from code/operators/operators.cpp rename to exercises/operators/operators.cpp diff --git a/code/operators/solution/operators.sol.cpp b/exercises/operators/solution/operators.sol.cpp similarity index 100% rename from code/operators/solution/operators.sol.cpp rename to exercises/operators/solution/operators.sol.cpp diff --git a/code/optional/CMakeLists.txt b/exercises/optional/CMakeLists.txt similarity index 100% rename from code/optional/CMakeLists.txt rename to exercises/optional/CMakeLists.txt diff --git a/code/optional/Makefile b/exercises/optional/Makefile similarity index 100% rename from code/optional/Makefile rename to exercises/optional/Makefile diff --git a/code/optional/README.md b/exercises/optional/README.md similarity index 100% rename from code/optional/README.md rename to exercises/optional/README.md diff --git a/code/optional/optional.cpp b/exercises/optional/optional.cpp similarity index 100% rename from code/optional/optional.cpp rename to exercises/optional/optional.cpp diff --git a/code/optional/solution/optional.sol.cpp b/exercises/optional/solution/optional.sol.cpp similarity index 100% rename from code/optional/solution/optional.sol.cpp rename to exercises/optional/solution/optional.sol.cpp diff --git a/code/polymorphism/CMakeLists.txt b/exercises/polymorphism/CMakeLists.txt similarity index 100% rename from code/polymorphism/CMakeLists.txt rename to exercises/polymorphism/CMakeLists.txt diff --git a/code/polymorphism/Makefile b/exercises/polymorphism/Makefile similarity index 100% rename from code/polymorphism/Makefile rename to exercises/polymorphism/Makefile diff --git a/code/polymorphism/Polygons.cpp b/exercises/polymorphism/Polygons.cpp similarity index 100% rename from code/polymorphism/Polygons.cpp rename to exercises/polymorphism/Polygons.cpp diff --git a/code/polymorphism/Polygons.hpp b/exercises/polymorphism/Polygons.hpp similarity index 100% rename from code/polymorphism/Polygons.hpp rename to exercises/polymorphism/Polygons.hpp diff --git a/code/polymorphism/README.md b/exercises/polymorphism/README.md similarity index 100% rename from code/polymorphism/README.md rename to exercises/polymorphism/README.md diff --git a/code/polymorphism/solution/trypoly.sol.cpp b/exercises/polymorphism/solution/trypoly.sol.cpp similarity index 100% rename from code/polymorphism/solution/trypoly.sol.cpp rename to exercises/polymorphism/solution/trypoly.sol.cpp diff --git a/code/polymorphism/trypoly.cpp b/exercises/polymorphism/trypoly.cpp similarity index 100% rename from code/polymorphism/trypoly.cpp rename to exercises/polymorphism/trypoly.cpp diff --git a/code/python/CMakeLists.txt b/exercises/python/CMakeLists.txt similarity index 100% rename from code/python/CMakeLists.txt rename to exercises/python/CMakeLists.txt diff --git a/code/python/Complex.hpp b/exercises/python/Complex.hpp similarity index 100% rename from code/python/Complex.hpp rename to exercises/python/Complex.hpp diff --git a/code/python/Makefile b/exercises/python/Makefile similarity index 100% rename from code/python/Makefile rename to exercises/python/Makefile diff --git a/code/python/README.md b/exercises/python/README.md similarity index 100% rename from code/python/README.md rename to exercises/python/README.md diff --git a/code/python/mandel.cpp b/exercises/python/mandel.cpp similarity index 100% rename from code/python/mandel.cpp rename to exercises/python/mandel.cpp diff --git a/code/python/mandel.hpp b/exercises/python/mandel.hpp similarity index 100% rename from code/python/mandel.hpp rename to exercises/python/mandel.hpp diff --git a/code/python/mandel.py b/exercises/python/mandel.py similarity index 100% rename from code/python/mandel.py rename to exercises/python/mandel.py diff --git a/code/python/mandel_cwrapper.cpp b/exercises/python/mandel_cwrapper.cpp similarity index 100% rename from code/python/mandel_cwrapper.cpp rename to exercises/python/mandel_cwrapper.cpp diff --git a/code/python/mandel_cwrapper.hpp b/exercises/python/mandel_cwrapper.hpp similarity index 100% rename from code/python/mandel_cwrapper.hpp rename to exercises/python/mandel_cwrapper.hpp diff --git a/code/python/mandel_module.cpp b/exercises/python/mandel_module.cpp similarity index 100% rename from code/python/mandel_module.cpp rename to exercises/python/mandel_module.cpp diff --git a/code/python/solution/mandel.sol.py b/exercises/python/solution/mandel.sol.py similarity index 100% rename from code/python/solution/mandel.sol.py rename to exercises/python/solution/mandel.sol.py diff --git a/code/python/solution/mandel.solctype.py b/exercises/python/solution/mandel.solctype.py similarity index 100% rename from code/python/solution/mandel.solctype.py rename to exercises/python/solution/mandel.solctype.py diff --git a/code/race/CMakeLists.txt b/exercises/race/CMakeLists.txt similarity index 100% rename from code/race/CMakeLists.txt rename to exercises/race/CMakeLists.txt diff --git a/code/race/Makefile b/exercises/race/Makefile similarity index 100% rename from code/race/Makefile rename to exercises/race/Makefile diff --git a/code/race/README.md b/exercises/race/README.md similarity index 100% rename from code/race/README.md rename to exercises/race/README.md diff --git a/code/race/racing.cpp b/exercises/race/racing.cpp similarity index 100% rename from code/race/racing.cpp rename to exercises/race/racing.cpp diff --git a/code/race/run b/exercises/race/run similarity index 100% rename from code/race/run rename to exercises/race/run diff --git a/code/race/solution/racing.sol.cpp b/exercises/race/solution/racing.sol.cpp similarity index 100% rename from code/race/solution/racing.sol.cpp rename to exercises/race/solution/racing.sol.cpp diff --git a/code/smartPointers/CMakeLists.txt b/exercises/smartPointers/CMakeLists.txt similarity index 100% rename from code/smartPointers/CMakeLists.txt rename to exercises/smartPointers/CMakeLists.txt diff --git a/code/smartPointers/Makefile b/exercises/smartPointers/Makefile similarity index 100% rename from code/smartPointers/Makefile rename to exercises/smartPointers/Makefile diff --git a/code/smartPointers/README.md b/exercises/smartPointers/README.md similarity index 100% rename from code/smartPointers/README.md rename to exercises/smartPointers/README.md diff --git a/code/smartPointers/smartPointers.cpp b/exercises/smartPointers/smartPointers.cpp similarity index 100% rename from code/smartPointers/smartPointers.cpp rename to exercises/smartPointers/smartPointers.cpp diff --git a/code/smartPointers/solution/smartPointers.sol.cpp b/exercises/smartPointers/solution/smartPointers.sol.cpp similarity index 100% rename from code/smartPointers/solution/smartPointers.sol.cpp rename to exercises/smartPointers/solution/smartPointers.sol.cpp diff --git a/code/spaceship/CMakeLists.txt b/exercises/spaceship/CMakeLists.txt similarity index 100% rename from code/spaceship/CMakeLists.txt rename to exercises/spaceship/CMakeLists.txt diff --git a/code/spaceship/Makefile b/exercises/spaceship/Makefile similarity index 100% rename from code/spaceship/Makefile rename to exercises/spaceship/Makefile diff --git a/code/spaceship/README.md b/exercises/spaceship/README.md similarity index 100% rename from code/spaceship/README.md rename to exercises/spaceship/README.md diff --git a/code/spaceship/solution/spaceship.sol.cpp b/exercises/spaceship/solution/spaceship.sol.cpp similarity index 100% rename from code/spaceship/solution/spaceship.sol.cpp rename to exercises/spaceship/solution/spaceship.sol.cpp diff --git a/code/spaceship/spaceship.cpp b/exercises/spaceship/spaceship.cpp similarity index 100% rename from code/spaceship/spaceship.cpp rename to exercises/spaceship/spaceship.cpp diff --git a/code/stl/CMakeLists.txt b/exercises/stl/CMakeLists.txt similarity index 100% rename from code/stl/CMakeLists.txt rename to exercises/stl/CMakeLists.txt diff --git a/code/stl/Complex.hpp b/exercises/stl/Complex.hpp similarity index 100% rename from code/stl/Complex.hpp rename to exercises/stl/Complex.hpp diff --git a/code/stl/Makefile b/exercises/stl/Makefile similarity index 100% rename from code/stl/Makefile rename to exercises/stl/Makefile diff --git a/code/stl/README.md b/exercises/stl/README.md similarity index 100% rename from code/stl/README.md rename to exercises/stl/README.md diff --git a/code/stl/randomize.cpp b/exercises/stl/randomize.cpp similarity index 100% rename from code/stl/randomize.cpp rename to exercises/stl/randomize.cpp diff --git a/code/stl/randomize.nostl.cpp b/exercises/stl/randomize.nostl.cpp similarity index 100% rename from code/stl/randomize.nostl.cpp rename to exercises/stl/randomize.nostl.cpp diff --git a/code/stl/solution/randomize.sol.cpp b/exercises/stl/solution/randomize.sol.cpp similarity index 100% rename from code/stl/solution/randomize.sol.cpp rename to exercises/stl/solution/randomize.sol.cpp diff --git a/code/templates/CMakeLists.txt b/exercises/templates/CMakeLists.txt similarity index 100% rename from code/templates/CMakeLists.txt rename to exercises/templates/CMakeLists.txt diff --git a/code/templates/Complex.hpp b/exercises/templates/Complex.hpp similarity index 100% rename from code/templates/Complex.hpp rename to exercises/templates/Complex.hpp diff --git a/code/templates/Makefile b/exercises/templates/Makefile similarity index 100% rename from code/templates/Makefile rename to exercises/templates/Makefile diff --git a/code/templates/OrderedVector.hpp b/exercises/templates/OrderedVector.hpp similarity index 100% rename from code/templates/OrderedVector.hpp rename to exercises/templates/OrderedVector.hpp diff --git a/code/templates/README.md b/exercises/templates/README.md similarity index 100% rename from code/templates/README.md rename to exercises/templates/README.md diff --git a/code/templates/playwithsort.cpp b/exercises/templates/playwithsort.cpp similarity index 100% rename from code/templates/playwithsort.cpp rename to exercises/templates/playwithsort.cpp diff --git a/code/templates/solution/OrderedVector.sol.hpp b/exercises/templates/solution/OrderedVector.sol.hpp similarity index 100% rename from code/templates/solution/OrderedVector.sol.hpp rename to exercises/templates/solution/OrderedVector.sol.hpp diff --git a/code/templates/solution/playwithsort.sol.cpp b/exercises/templates/solution/playwithsort.sol.cpp similarity index 100% rename from code/templates/solution/playwithsort.sol.cpp rename to exercises/templates/solution/playwithsort.sol.cpp diff --git a/code/valgrind/CMakeLists.txt b/exercises/valgrind/CMakeLists.txt similarity index 100% rename from code/valgrind/CMakeLists.txt rename to exercises/valgrind/CMakeLists.txt diff --git a/code/valgrind/Makefile b/exercises/valgrind/Makefile similarity index 100% rename from code/valgrind/Makefile rename to exercises/valgrind/Makefile diff --git a/code/valgrind/README.md b/exercises/valgrind/README.md similarity index 100% rename from code/valgrind/README.md rename to exercises/valgrind/README.md diff --git a/code/valgrind/debug.cpp b/exercises/valgrind/debug.cpp similarity index 100% rename from code/valgrind/debug.cpp rename to exercises/valgrind/debug.cpp diff --git a/code/valgrind/solution/debug.sol.cpp b/exercises/valgrind/solution/debug.sol.cpp similarity index 100% rename from code/valgrind/solution/debug.sol.cpp rename to exercises/valgrind/solution/debug.sol.cpp diff --git a/code/variadic/CMakeLists.txt b/exercises/variadic/CMakeLists.txt similarity index 100% rename from code/variadic/CMakeLists.txt rename to exercises/variadic/CMakeLists.txt diff --git a/code/variadic/Makefile b/exercises/variadic/Makefile similarity index 100% rename from code/variadic/Makefile rename to exercises/variadic/Makefile diff --git a/code/variadic/README.md b/exercises/variadic/README.md similarity index 100% rename from code/variadic/README.md rename to exercises/variadic/README.md diff --git a/code/variadic/solution/variadic.sol.cpp b/exercises/variadic/solution/variadic.sol.cpp similarity index 100% rename from code/variadic/solution/variadic.sol.cpp rename to exercises/variadic/solution/variadic.sol.cpp diff --git a/code/variadic/variadic.cpp b/exercises/variadic/variadic.cpp similarity index 100% rename from code/variadic/variadic.cpp rename to exercises/variadic/variadic.cpp diff --git a/code/variant/CMakeLists.txt b/exercises/variant/CMakeLists.txt similarity index 100% rename from code/variant/CMakeLists.txt rename to exercises/variant/CMakeLists.txt diff --git a/code/variant/Makefile b/exercises/variant/Makefile similarity index 100% rename from code/variant/Makefile rename to exercises/variant/Makefile diff --git a/code/variant/README.md b/exercises/variant/README.md similarity index 100% rename from code/variant/README.md rename to exercises/variant/README.md diff --git a/code/variant/solution/variant.sol1.cpp b/exercises/variant/solution/variant.sol1.cpp similarity index 100% rename from code/variant/solution/variant.sol1.cpp rename to exercises/variant/solution/variant.sol1.cpp diff --git a/code/variant/solution/variant.sol2.cpp b/exercises/variant/solution/variant.sol2.cpp similarity index 100% rename from code/variant/solution/variant.sol2.cpp rename to exercises/variant/solution/variant.sol2.cpp diff --git a/code/variant/variant.cpp b/exercises/variant/variant.cpp similarity index 100% rename from code/variant/variant.cpp rename to exercises/variant/variant.cpp diff --git a/code/virtual_inheritance/CMakeLists.txt b/exercises/virtual_inheritance/CMakeLists.txt similarity index 100% rename from code/virtual_inheritance/CMakeLists.txt rename to exercises/virtual_inheritance/CMakeLists.txt diff --git a/code/virtual_inheritance/Makefile b/exercises/virtual_inheritance/Makefile similarity index 100% rename from code/virtual_inheritance/Makefile rename to exercises/virtual_inheritance/Makefile diff --git a/code/virtual_inheritance/README.md b/exercises/virtual_inheritance/README.md similarity index 100% rename from code/virtual_inheritance/README.md rename to exercises/virtual_inheritance/README.md diff --git a/code/virtual_inheritance/TextBox.cpp b/exercises/virtual_inheritance/TextBox.cpp similarity index 100% rename from code/virtual_inheritance/TextBox.cpp rename to exercises/virtual_inheritance/TextBox.cpp diff --git a/code/virtual_inheritance/TextBox.hpp b/exercises/virtual_inheritance/TextBox.hpp similarity index 100% rename from code/virtual_inheritance/TextBox.hpp rename to exercises/virtual_inheritance/TextBox.hpp diff --git a/code/virtual_inheritance/solution/TextBox.cpp b/exercises/virtual_inheritance/solution/TextBox.cpp similarity index 100% rename from code/virtual_inheritance/solution/TextBox.cpp rename to exercises/virtual_inheritance/solution/TextBox.cpp diff --git a/code/virtual_inheritance/solution/TextBox.hpp b/exercises/virtual_inheritance/solution/TextBox.hpp similarity index 100% rename from code/virtual_inheritance/solution/TextBox.hpp rename to exercises/virtual_inheritance/solution/TextBox.hpp diff --git a/code/virtual_inheritance/solution/trymultiherit.sol.cpp b/exercises/virtual_inheritance/solution/trymultiherit.sol.cpp similarity index 100% rename from code/virtual_inheritance/solution/trymultiherit.sol.cpp rename to exercises/virtual_inheritance/solution/trymultiherit.sol.cpp diff --git a/code/virtual_inheritance/trymultiherit.cpp b/exercises/virtual_inheritance/trymultiherit.cpp similarity index 100% rename from code/virtual_inheritance/trymultiherit.cpp rename to exercises/virtual_inheritance/trymultiherit.cpp diff --git a/talk/basicconcepts/auto.tex b/talk/basicconcepts/auto.tex index f0fc9b5a..331dd76a 100644 --- a/talk/basicconcepts/auto.tex +++ b/talk/basicconcepts/auto.tex @@ -31,7 +31,7 @@ \begin{exerciseWithShortcut}{Loops, references, auto}{Loops, refs, auto} Familiarise yourself with range-based for loops and references \begin{itemize} - \item Go to \texttt{code/loopsRefsAuto} + \item Go to \texttt{exercises/loopsRefsAuto} \item Look at \texttt{loopsRefsAuto.cpp} \item Compile it (\texttt{make}) and run the program (\texttt{./loopsRefsAuto}) \item Work on the tasks that you find in \texttt{loopsRefsAuto.cpp} diff --git a/talk/basicconcepts/control.tex b/talk/basicconcepts/control.tex index 904e15ce..7e83b449 100644 --- a/talk/basicconcepts/control.tex +++ b/talk/basicconcepts/control.tex @@ -304,7 +304,7 @@ \begin{exerciseWithShortcut}{Control structures}{Control structs} Familiarise yourself with different kinds of control structures. Re-implement them in different ways. \begin{itemize} - \item Go to \texttt{code/control} + \item Go to \texttt{exercises/control} \item Look at \texttt{control.cpp} \item Compile it (\texttt{make}) and run the program (\texttt{./control}) \item Work on the tasks that you find in \texttt{README.md} diff --git a/talk/basicconcepts/functions.tex b/talk/basicconcepts/functions.tex index 7c12b750..29bd3f66 100644 --- a/talk/basicconcepts/functions.tex +++ b/talk/basicconcepts/functions.tex @@ -242,7 +242,7 @@ \begin{exercise}{Functions} Familiarise yourself with pass by value / pass by reference. \begin{itemize} - \item Go to \texttt{code/functions} + \item Go to \texttt{exercises/functions} \item Look at \texttt{functions.cpp} \item Compile it (\texttt{make}) and run the program (\texttt{./functions}) \item Work on the tasks that you find in \texttt{functions.cpp} diff --git a/talk/concurrency/atomic.tex b/talk/concurrency/atomic.tex index ae3c7062..fc2e3081 100644 --- a/talk/concurrency/atomic.tex +++ b/talk/concurrency/atomic.tex @@ -118,7 +118,7 @@ \frametitle{Atomic types in \cpp} \begin{exercise}{Atomics} \begin{itemize} - \item Go to \texttt{code/atomic} + \item Go to \texttt{exercises/atomic} \item You'll find a program with the same race condition as in \texttt{race} \item Fix it using \cppinline{std::atomic} \end{itemize} diff --git a/talk/concurrency/condition.tex b/talk/concurrency/condition.tex index 07eadb06..c2182214 100644 --- a/talk/concurrency/condition.tex +++ b/talk/concurrency/condition.tex @@ -117,7 +117,7 @@ \frametitle{Condition variables} \begin{exerciseWithShortcut}{Condition variables}{Condition vars} \begin{itemize} - \item Go to code/condition\_variable + \item Go to \texttt{exercises/condition\_variable} \item Look at the code and run it\\ See that it has a race condition \item Fix the race condition in the usage of the condition variable diff --git a/talk/concurrency/mutexes.tex b/talk/concurrency/mutexes.tex index e35861f6..6a118d9e 100644 --- a/talk/concurrency/mutexes.tex +++ b/talk/concurrency/mutexes.tex @@ -18,7 +18,7 @@ \end{cppcode*} \end{exampleblockGB} \pause - \begin{block}{What do you expect? (Exercise code/race)} + \begin{block}{What do you expect? (Exercise exercises/race)} \pause Anything between 100 and 200 !!! \end{block} @@ -137,7 +137,7 @@ \frametitle{Mutexes and Locks} \begin{exerciseWithShortcut}{Mutexes and Locks}{Mutexes/Locks} \begin{itemize} - \item Go to code/race + \item Go to \texttt{exercises/race} \item Look at the code and try it\\ See that it has a race condition \item Use a mutex to fix the issue diff --git a/talk/expert/cpp20concepts.tex b/talk/expert/cpp20concepts.tex index 3b1631a9..fe40b2cb 100644 --- a/talk/expert/cpp20concepts.tex +++ b/talk/expert/cpp20concepts.tex @@ -283,7 +283,7 @@ \frametitlecpp[20]{Exercise time} \begin{exercise}{Concepts} \begin{itemize} - \item go to code/concepts + \item go to \texttt{exercises/concepts} \item you will use concepts to optimize some loop on iterators \item follow the instructions in the source code \end{itemize} diff --git a/talk/expert/modules.tex b/talk/expert/modules.tex index cc32e014..56dddd65 100644 --- a/talk/expert/modules.tex +++ b/talk/expert/modules.tex @@ -659,13 +659,13 @@ \frametitlecpp[20]{Modules} \begin{exercise}{Modules} \begin{itemize} - \item go to \texttt{code/modules} + \item go to \texttt{exercises/modules} \item convert the \texttt{Complex.hpp} header into a module named \texttt{math} \end{itemize} \end{exercise} \begin{exercise}{Header units} \begin{itemize} - \item go to \texttt{code/header\_units} + \item go to \texttt{exercises/header\_units} \item convert all \cppinline{#include}s into header unit \cppinline{import}s \end{itemize} \end{exercise} diff --git a/talk/expert/variadictemplate.tex b/talk/expert/variadictemplate.tex index 1a5da4e5..be012f95 100644 --- a/talk/expert/variadictemplate.tex +++ b/talk/expert/variadictemplate.tex @@ -210,7 +210,7 @@ \frametitlecpp[11]{Variadic templates} \begin{exerciseWithShortcut}{Variadic templates}{Variadic tpl} \begin{itemize} - \item go to code/variadic + \item go to \texttt{exercises/variadic} \item you will extend the \cppinline{tuple} from the last slides \item follow the instructions in the source code \end{itemize} diff --git a/talk/morelanguage/constness.tex b/talk/morelanguage/constness.tex index f5493a6a..ede4ade1 100644 --- a/talk/morelanguage/constness.tex +++ b/talk/morelanguage/constness.tex @@ -98,7 +98,7 @@ \frametitlecpp[98]{constness} \begin{exercise}{Constness} \begin{itemize} - \item go to code/constness + \item go to \texttt{exercises/constness} \item open constplay.cpp \item try to find out which lines won't compile \item check your guesses by compiling for real diff --git a/talk/morelanguage/morestl.tex b/talk/morelanguage/morestl.tex index 0617876d..561143fe 100644 --- a/talk/morelanguage/morestl.tex +++ b/talk/morelanguage/morestl.tex @@ -140,7 +140,7 @@ \frametitlecpp[17]{std::optional} \begin{exerciseWithShortcut}{Handling optional results}{std::optional} \begin{itemize} - \item go to \texttt{code/optional/optional.cpp} + \item go to \texttt{exercises/optional/optional.cpp} \item modify \texttt{mysqrt} so to return an \texttt{std::optional} \item guess the consequences on \texttt{square} \end{itemize} @@ -234,7 +234,7 @@ \frametitlecpp[17]{std::variant exercise} \begin{exerciseWithShortcut}{An alternative to oo polymorphism}{std::variant} \begin{itemize} - \item go to \texttt{code/variant/variant.cpp} + \item go to \texttt{exercises/variant/variant.cpp} \item replace inheritance from a common base class with an \cppinline{std::variant} on the three kinds of particle. \item two solutions given : with \cppinline{std::get_if} and with \cppinline{std::visit}. \end{itemize} diff --git a/talk/morelanguage/move.tex b/talk/morelanguage/move.tex index 455c6bac..85da62e0 100644 --- a/talk/morelanguage/move.tex +++ b/talk/morelanguage/move.tex @@ -271,7 +271,7 @@ \frametitlecpp[11]{Move Semantic} \begin{exercise}{Move semantics} \begin{itemize} - \item go to code/move + \item go to \texttt{exercises/move} \item look at the code and run it with callgrind \item understand how inefficient it is \item implement move semantic the easy way in NVector diff --git a/talk/morelanguage/raii.tex b/talk/morelanguage/raii.tex index c305cb32..3f0d358e 100644 --- a/talk/morelanguage/raii.tex +++ b/talk/morelanguage/raii.tex @@ -453,7 +453,7 @@ \frametitlecpp[98]{smart pointers} \begin{exercise}{Smart pointers} \begin{itemize} - \item go to code/smartPointers + \item go to \texttt{exercises/smartPointers} \item compile and run the program. It doesn't generate any output. \item Run with valgrind if possible to check for leaks { \scriptsize diff --git a/talk/morelanguage/stl.tex b/talk/morelanguage/stl.tex index 09b1b757..f4555c53 100644 --- a/talk/morelanguage/stl.tex +++ b/talk/morelanguage/stl.tex @@ -375,7 +375,7 @@ \frametitlecpp[98]{Using the STL} \begin{exercise}{STL} \begin{itemize} - \item go to code/stl + \item go to \texttt{exercises/stl} \item look at the non STL code in randomize.nostl.cpp \begin{itemize} \item it creates a vector of ints at regular intervals diff --git a/talk/morelanguage/templates.tex b/talk/morelanguage/templates.tex index 52c492a2..f241359a 100644 --- a/talk/morelanguage/templates.tex +++ b/talk/morelanguage/templates.tex @@ -488,7 +488,7 @@ \frametitlecpp[98]{The full power of templates} \begin{exercise}{Templates} \begin{itemize} - \item go to code/templates + \item go to \texttt{exercises/templates} \item look at the OrderedVector code \item compile and run playwithsort.cpp. See the ordering \item modify playwithsort.cpp and reuse OrderedVector with Complex diff --git a/talk/objectorientation/advancedoo.tex b/talk/objectorientation/advancedoo.tex index 31ec8b90..4074d2e7 100644 --- a/talk/objectorientation/advancedoo.tex +++ b/talk/objectorientation/advancedoo.tex @@ -419,7 +419,7 @@ \frametitlecpp[98]{Polymorphism} \begin{exercise}{Polymorphism} \begin{itemize} - \item go to code/polymorphism + \item go to \texttt{exercises/polymorphism} \item look at the code \item open trypoly.cpp \item create a Pentagon, call its perimeter method @@ -549,7 +549,7 @@ \frametitlecpp[98]{Virtual inheritance} \begin{exerciseWithShortcut}{Virtual inheritance}{Virtual OO} \begin{itemize} - \item go to code/virtual\_inheritance + \item go to \texttt{exercisescode/virtual\_inheritance} \item look at the code \item open trymultiherit.cpp \item create a TextBox and call draw diff --git a/talk/objectorientation/operators.tex b/talk/objectorientation/operators.tex index bfcca357..fe86d09f 100644 --- a/talk/objectorientation/operators.tex +++ b/talk/objectorientation/operators.tex @@ -118,7 +118,7 @@ \begin{exercise}{Operators} Write a simple class representing a fraction and pass all tests \begin{itemize} - \item go to \texttt{code/operators} + \item go to \texttt{exercises/operators} \item look at \texttt{operators.cpp} \item inspect \cppinline{main} and complete the implementation of \cppinline{class Fraction} step by step \item you can comment out parts of \cppinline{main} to test in between diff --git a/talk/python/ctypes.tex b/talk/python/ctypes.tex index 63474960..bc81e4e6 100644 --- a/talk/python/ctypes.tex +++ b/talk/python/ctypes.tex @@ -40,7 +40,7 @@ \frametitle{Marrying \cpp and python} \begin{exercise}{\cpp and python} \begin{itemize} - \item go to code/python + \item go to \texttt{exercises/python} \item look at the original python code mandel.py \item time it (`time python3 mandel.py`) \item look at the code in mandel.hpp/cpp diff --git a/talk/python/modulewriting.tex b/talk/python/modulewriting.tex index 44b0117d..b3095d00 100644 --- a/talk/python/modulewriting.tex +++ b/talk/python/modulewriting.tex @@ -11,7 +11,7 @@ \begin{frame}[fragile] \frametitle{Basic Module(1): wrap your method} - \begin{block}{mandelModule.cpp - see code/python exercise} + \begin{block}{mandelModule.cpp - see exercises/python exercise} \begin{cppcode*}{} #include #include "mandel.hpp" @@ -32,7 +32,7 @@ \begin{frame}[fragile] \frametitle{Basic Module(2): create the python module} - \begin{block}{mandelModule.cpp - see code/python exercise} + \begin{block}{mandelModule.cpp - see exercises/python exercise} \begin{cppcode*}{} // declare the modules' methods PyMethodDef mandelMethods[] = { @@ -60,7 +60,7 @@ \item with '\mintinline{bash}{-I \$(PYTHON\_INCLUDE)}' \end{itemize} \end{block} - \begin{block}{mandel.py - see code/python exercise} + \begin{block}{mandel.py - see exercises/python exercise} \begin{minted}[gobble=4]{python} from mandel import mandel v = mandel(0.7, 1.2) diff --git a/talk/tools/compiling.tex b/talk/tools/compiling.tex index fafc9fb9..e459ed58 100644 --- a/talk/tools/compiling.tex +++ b/talk/tools/compiling.tex @@ -212,7 +212,7 @@ \frametitle{Compiler chain} \begin{exercise}{Compiler chain} \begin{itemize} - \item go to code/polymorphism + \item go to \texttt{exercises/polymorphism} \item preprocess Polygons.cpp (g++ -E -o output) \item compile Polygons.o and trypoly.o (g++ -c -o output) \item use nm to check symbols in .o files diff --git a/talk/tools/debugging.tex b/talk/tools/debugging.tex index 91ed016d..e68f3b15 100644 --- a/talk/tools/debugging.tex +++ b/talk/tools/debugging.tex @@ -58,7 +58,7 @@ \frametitle{gdb} \begin{exercise}{gdb} \begin{itemize} - \item go to code/debug + \item go to \texttt{exercises/debug} \item compile, run, see the crash \item run it in gdb (or lldb on newer MacOS) \item inspect backtrace, variables diff --git a/talk/tools/formatting.tex b/talk/tools/formatting.tex index 2f611466..04f9e808 100644 --- a/talk/tools/formatting.tex +++ b/talk/tools/formatting.tex @@ -30,7 +30,7 @@ \item Format code with: \mintinline{bash}{clang-format --style=GNU -i } \item Inspect changes, try \mintinline{bash}{git diff .} \item Revert changes using \mintinline{bash}{git checkout -- } or \mintinline{bash}{git checkout .} - \item Go to code directory and create a .clang-format file \\ + \item Go to \texttt{exercises} directory and create a .clang-format file \\ \mintinline{bash}{clang-format -style=LLVM -dump-config >} \\ \mintinline{bash}{.clang-format} \item Run \mintinline{bash}{clang-format -i /*.cpp} diff --git a/talk/tools/sanitizers.tex b/talk/tools/sanitizers.tex index 3be80ab8..c3498445 100644 --- a/talk/tools/sanitizers.tex +++ b/talk/tools/sanitizers.tex @@ -203,7 +203,7 @@ \frametitle{Address sanitizer (ASan)} \begin{exercise}{address sanitizer} \begin{itemize} - \item Go to \texttt{code/asan} + \item Go to \texttt{exercises/asan} \item Compile and run the program \texttt{./asan} \item There are two bugs and one memory leak. Use asan to trace them down. \end{itemize} diff --git a/talk/tools/staticanalysis.tex b/talk/tools/staticanalysis.tex index 2a311e8e..a3e4a66e 100644 --- a/talk/tools/staticanalysis.tex +++ b/talk/tools/staticanalysis.tex @@ -34,7 +34,7 @@ \frametitle{cppcheck} \begin{exercise}{cppcheck} \begin{itemize} - \item go to code/cppcheck + \item go to \texttt{exercises/cppcheck} \item compile, run, see that it works \item use valgrind: no issue \item use cppcheck, see the problem @@ -97,7 +97,7 @@ \frametitle{clang-tidy} \begin{exercise}{clang-tidy} \begin{itemize} - \item go to any example which compiles (e.g. code/cppcheck) + \item go to any example which compiles (e.g. \texttt{exercises/cppcheck}) \item \mintinline{bash}{mkdir build && cd build} \item \mintinline{bash}{cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..} \item \mintinline{bash}{clang-tidy <../file.cpp> -checks=*} diff --git a/talk/tools/valgrind.tex b/talk/tools/valgrind.tex index 668befc5..2bd53546 100644 --- a/talk/tools/valgrind.tex +++ b/talk/tools/valgrind.tex @@ -43,12 +43,12 @@ \frametitle{valgrind} \begin{exercise}{valgrind} \begin{itemize} - \item go to code/valgrind + \item go to \texttt{exercises/valgrind} \item compile, run, it should work \item run with valgrind, see the problem \item fix the problem \vspace{.3cm} - \item go back to the code/debug exercise + \item go back to the \texttt{exercises/debug} exercise \item check it with valgrind \item analyze the issue, see that the variance was biaised \item fix the issue @@ -60,7 +60,7 @@ \frametitle{memcheck} \begin{exercise}{memcheck} \begin{itemize} - \item go to code/memcheck + \item go to \texttt{exercises/memcheck} \item compile, run, it should work \item run with valgrind, see LEAK summary \item run with -{}-leak-check=full to get details @@ -92,7 +92,7 @@ \frametitle{callgrind} \begin{exercise}{callgrind} \begin{itemize} - \item go to code/callgrind + \item go to \texttt{exercises/callgrind} \item compile, run, it will be slow \item change nb iterations to 20 \item run with valgrind -{}-tool=callgrind @@ -127,7 +127,7 @@ \frametitle{helgrind} \begin{exercise}{helgrind} \begin{itemize} - \item go to code/helgrind + \item go to \texttt{exercises/helgrind} \item compile, run \item check it with valgrind. You may see strange behavior \\ or it will be perfectly fine From 5190be7b11b2708ce681dab8766df3d64f14c94c Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 23 Jun 2023 14:31:41 +0200 Subject: [PATCH 030/156] Discuss using declarations/directives Add a slide on "using namespace" and using declarations. This is mostly to address using namespace std, which students will see in their life as a programmer. Fix #461 --- talk/basicconcepts/scopesnamespaces.tex | 29 +++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/talk/basicconcepts/scopesnamespaces.tex b/talk/basicconcepts/scopesnamespaces.tex index 1bea11f2..d3995b79 100644 --- a/talk/basicconcepts/scopesnamespaces.tex +++ b/talk/basicconcepts/scopesnamespaces.tex @@ -183,4 +183,33 @@ \end{cppcode*} \end{alertblock} \end{frame} + +\begin{frame}[fragile] + \frametitlecpp[98]{Using namespace directives} + \begin{alertblock}{Avoid ``using namespace'' directives} + \begin{itemize} + \item Make all members of a namespace visible in current scope + \item Risk of name clashes or ambiguities + \end{itemize} + \begin{cppcode*}{} + using namespace std; + cout << "We can print now\n"; // uses std::cout + \end{cppcode*} + \end{alertblock} + \begin{alertblock}{Never use in headers at global scope!} + \begin{cppcode*}{gobble=2} + #include "PoorlyWritten.h" // using namespace std; + struct array { ... }; + array a; // Error: name clash with std::array + \end{cppcode*} + \end{alertblock} + \begin{block}{What to do instead} + \begin{itemize} + \item Qualify names: \cppinline{std::vector}, \cppinline{std::cout}, \ldots + \item Put things that belong together in the same namespace + \item Use \textit{using declarations} in local scopes: \cppinline{using std::cout;} + \end{itemize} + \end{block} +\end{frame} + \end{advanced} From 0b51a8f594c4dfe97f6b0a55862dc4d6c919edf9 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Wed, 28 Jun 2023 10:48:31 +0200 Subject: [PATCH 031/156] Fix a tikz positioning directive that points to a non-existing element. --- talk/objectorientation/advancedoo.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/talk/objectorientation/advancedoo.tex b/talk/objectorientation/advancedoo.tex index 4074d2e7..149caeaf 100644 --- a/talk/objectorientation/advancedoo.tex +++ b/talk/objectorientation/advancedoo.tex @@ -504,7 +504,7 @@ \end{block} \begin{multicols}{2} \begin{tikzpicture}[] - \classbox[below of=title]{Drawable}{} + \classbox{Drawable}{} \classbox[below left of=Drawable,node distance=2cm]{Rectangle}{} \classbox[right of=Rectangle,node distance=3cm]{Text}{} \classbox[below right of=Rectangle,node distance=2cm]{TextBox}{} From 23827f447c3d92c1ec2b89cb30ef407a35d76d30 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 10 Jul 2023 15:58:55 -0400 Subject: [PATCH 032/156] [pre-commit.ci] pre-commit autoupdate (#481) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/codespell-project/codespell: v2.2.4 → v2.2.5](https://github.com/codespell-project/codespell/compare/v2.2.4...v2.2.5) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 60e9ba43..07803899 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/codespell-project/codespell - rev: 'v2.2.4' + rev: 'v2.2.5' hooks: - id: codespell args: ["-I", "codespell.txt"] From 178b01fa7b3a7d569e979457a41970eec544dafc Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Tue, 8 Aug 2023 11:43:09 +0200 Subject: [PATCH 033/156] Add Link to indico agenda to README --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 82409239..54165e78 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,10 @@ This repository contains all material for the C++ Course taught at CERN from Sebastien Ponce (LHCb). +## Next events + +Please check the [Indico agenda](https://indico.cern.ch/category/11733/). + ## 📎 Getting the latest PDF For each commit to master, the slides are compiled to a PDF and uploaded to the [download](https://github.com/hsf-training/cpluspluscourse/tree/download) branch. From 7564d5cad9c3e76b91fc9fdca1bcbc576a689e1b Mon Sep 17 00:00:00 2001 From: Kilian Lieret Date: Thu, 24 Aug 2023 13:32:46 +0200 Subject: [PATCH 034/156] List recent events (#483) --- README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 54165e78..e08580bc 100644 --- a/README.md +++ b/README.md @@ -28,11 +28,13 @@ For each commit to master, the slides are compiled to a PDF and uploaded to the Video recordings are available in the past events. -* [6th HEP C++ Course and Hands-on Training (2023 March - essentials)](https://indico.cern.ch/event/1229412/) -* [5th HEP C++ Course and Hands-on Training (2022 October - advanced)](https://indico.cern.ch/event/1172498/) -* [4nd HEP C++ Course and Hands-on Training (2022 March - essentials)](https://indico.cern.ch/event/1119339/) -* [3rd HEP C++ Course and Hands-on Training (2021 August)](https://indico.cern.ch/event/1019089/) -* [2nd HEP C++ Course and Hands-on Training (2021 January)](https://indico.cern.ch/event/979067/) +* [8th HEP C++ Course and Hands-on Training (essentials), Manchester, August 2023](https://indico.cern.ch/event/1266661/) +* [7th HEP C++ Course and Hands-on Training (essentials), JLAB, May 2023](https://indico.cern.ch/event/1266632/) +* [6th HEP C++ Course and Hands-on Training (essentials), CERN, March 2023](https://indico.cern.ch/event/1229412/) +* [5th HEP C++ Course and Hands-on Training (advanced), CERN, October 2022](https://indico.cern.ch/event/1172498/) +* [4nd HEP C++ Course and Hands-on Training (essentials), CERN, March 2022](https://indico.cern.ch/event/1119339/) +* [3rd HEP C++ Course and Hands-on Training, CERN, August 2021](https://indico.cern.ch/event/1019089/) +* [2nd HEP C++ Course and Hands-on Training, virtual, January 2021](https://indico.cern.ch/event/979067/) * [1st HEP C++ Course and Hands-on Training (2020 October)](https://indico.cern.ch/event/946584/) Check [this page](https://hepsoftwarefoundation.org/Schools/events.html) for announcements of upcoming training events (including those with this material). From 3507bdf890367dcacd9de043d5cb57680b6d87d1 Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Mon, 28 Aug 2023 17:12:16 +0200 Subject: [PATCH 035/156] Small corrections found while preparing Machester's course In details : - fixed indentation in arrayspointers (tabs were present breaking some slides) - fixed typo in coresyntax comments - moved "useful aliases" slide to advanced - tiny improvement in functions (usage of a ref) --- talk/basicconcepts/arrayspointers.tex | 38 +++++++++++++-------------- talk/basicconcepts/coresyntax.tex | 4 +-- talk/basicconcepts/functions.tex | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/talk/basicconcepts/arrayspointers.tex b/talk/basicconcepts/arrayspointers.tex index 90f99312..abbbd65a 100644 --- a/talk/basicconcepts/arrayspointers.tex +++ b/talk/basicconcepts/arrayspointers.tex @@ -114,23 +114,23 @@ \end{frame} \begin{frame}[fragile] - \frametitlecpp[98]{Manual dynamic arrays using \cpp} - \begin{cppcode} - #include - #include - - // allocate array of 10 ints - int* ai = new int[10]; // uninitialized - int* ai = new int[10]{}; // zero-initialized - - delete[] ai; // release array memory - - // allocate a single int - int* pi = new int; - int* pi = new int{}; - delete pi; // release scalar memory - \end{cppcode} - \begin{goodpracticeWithShortcut}{Don't use manual memory management}{Manual memory management} - Use \cppinline{std::vector} and friends or smart pointers - \end{goodpracticeWithShortcut} + \frametitlecpp[98]{Manual dynamic arrays using \cpp} + \begin{cppcode} + #include + #include + + // allocate array of 10 ints + int* ai = new int[10]; // uninitialized + int* ai = new int[10]{}; // zero-initialized + + delete[] ai; // release array memory + + // allocate a single int + int* pi = new int; + int* pi = new int{}; + delete pi; // release scalar memory + \end{cppcode} + \begin{goodpracticeWithShortcut}{Don't use manual memory management}{Manual memory management} + Use \cppinline{std::vector} and friends or smart pointers + \end{goodpracticeWithShortcut} \end{frame} diff --git a/talk/basicconcepts/coresyntax.tex b/talk/basicconcepts/coresyntax.tex index 97017f05..11362fad 100644 --- a/talk/basicconcepts/coresyntax.tex +++ b/talk/basicconcepts/coresyntax.tex @@ -132,7 +132,7 @@ double d = 123'456.789'101; // digit separators, C++14 - double d = 0x4d2.4p3; // hexfloat, 0x4d2.1 * 2^3 + double d = 0x4d2.4p3; // hexfloat, 0x4d2.4 * 2^3 // = 1234.25 * 2^3 = 9874 3.14f, 3.14F, // float @@ -141,6 +141,7 @@ \end{cppcode} \end{frame} +\begin{advanced} \begin{frame}[fragile] \frametitlecpp[98]{Useful aliases} \begin{cppcode} @@ -160,7 +161,6 @@ \end{cppcode} \end{frame} -\begin{advanced} \begin{frame}[fragile] \frametitlecpp[23]{Extended floating-point types} \begin{block}{Extended floating-point types} diff --git a/talk/basicconcepts/functions.tex b/talk/basicconcepts/functions.tex index 29bd3f66..218a6e72 100644 --- a/talk/basicconcepts/functions.tex +++ b/talk/basicconcepts/functions.tex @@ -265,7 +265,7 @@ \begin{cppcode*}{gobble=2} /// Count number of dilepton events in data. /// \param d Dataset to search. - unsigned int countDileptons(Data d) { + unsigned int countDileptons(Data &d) { selectEventsWithMuons(d); selectEventsWithElectrons(d); return d.size(); From 62e8bb8632952938d3d5ab3faee1bc4dce58d653 Mon Sep 17 00:00:00 2001 From: Kilian Lieret Date: Thu, 24 Aug 2023 12:11:48 +0200 Subject: [PATCH 036/156] Add markdown link checker --- .github/workflows/check-links.yaml | 14 ++++++++++++++ mlc_config.json | 13 +++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 .github/workflows/check-links.yaml create mode 100644 mlc_config.json diff --git a/.github/workflows/check-links.yaml b/.github/workflows/check-links.yaml new file mode 100644 index 00000000..0990af83 --- /dev/null +++ b/.github/workflows/check-links.yaml @@ -0,0 +1,14 @@ +name: Check Markdown links + +on: + push: + pull_request: + schedule: + - cron: "0 0 1 * *" + +jobs: + markdown-link-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - uses: gaurav-nelson/github-action-markdown-link-check@v1 diff --git a/mlc_config.json b/mlc_config.json new file mode 100644 index 00000000..9a237e69 --- /dev/null +++ b/mlc_config.json @@ -0,0 +1,13 @@ +{ + "ignorePatterns": [ + { + "pattern": "https://github.com/issues?.*" + }, + { + "pattern": ".*cookiecutter.*" + }, + { + "pattern": ".*opensource.*" + } + ] +} From e2f1430b0e180a982fb19653ea9d9dc305ea30e5 Mon Sep 17 00:00:00 2001 From: Kilian Lieret Date: Thu, 24 Aug 2023 12:14:28 +0200 Subject: [PATCH 037/156] Ignore download links --- mlc_config.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mlc_config.json b/mlc_config.json index 9a237e69..f9b4ab75 100644 --- a/mlc_config.json +++ b/mlc_config.json @@ -8,6 +8,9 @@ }, { "pattern": ".*opensource.*" + }, + { + "pattern": "https://github.com/hsf-training/cpluspluscourse/raw/download/.*" } ] } From 0c306cb2dbbc89cd406674319759d31748fbff69 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Wed, 30 Aug 2023 16:26:56 +0200 Subject: [PATCH 038/156] Move <=> to beginning of expert chapter. --- talk/C++Course.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/talk/C++Course.tex b/talk/C++Course.tex index 855061a2..a1fb6c00 100644 --- a/talk/C++Course.tex +++ b/talk/C++Course.tex @@ -172,11 +172,11 @@ \begin{advanced} \section[exp]{Expert \cpp} + \input{expert/cpp20spaceship} \input{expert/variadictemplate} \input{expert/perfectforwarding} \input{expert/sfinae} \input{expert/cpp20concepts} - \input{expert/cpp20spaceship} \input{expert/modules} \input{expert/coroutines} \end{advanced} From 6ed1585cf34d8fd60b5322a86303f79df346c48a Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Wed, 30 Aug 2023 16:27:04 +0200 Subject: [PATCH 039/156] Minor formatting fixes for concepts section. --- talk/expert/cpp20concepts.tex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/talk/expert/cpp20concepts.tex b/talk/expert/cpp20concepts.tex index fe40b2cb..669c2256 100644 --- a/talk/expert/cpp20concepts.tex +++ b/talk/expert/cpp20concepts.tex @@ -14,7 +14,7 @@ \begin{frame}[fragile] \frametitlecpp[17]{The world before concepts} - \begin{block}{\cpp17 work around : SFINAE} + \begin{block}{\cpp17 work around: SFINAE} \begin{itemize} \item Unsuited arguments can be avoided by inserting fake template arguments, leading to a substitution failure @@ -133,7 +133,7 @@ \frametitlecpp[20]{Some usages of concepts} \begin{block}{Constrained template parameters} \begin{itemize} - \item a concept can replace \cppinline{typename} in a template parameter lists + \item a concept can replace \cppinline{typename} in a template parameter list \end{itemize} \end{block} \begin{exampleblock}{} @@ -261,7 +261,7 @@ \end{cppcode*} \end{exampleblock} \begin{block}{} - Remember : use standard concepts first + Remember: use standard concepts first \end{block} \end{frame} From 79b509bc152a0b2b19a493110b2b28bae7b87a6a Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Wed, 30 Aug 2023 17:37:21 +0200 Subject: [PATCH 040/156] Dropped useless bigdata member in the functions example It served no purpose (copy was not slow there, only a sleep made it slow) and was discovered (the hard way) to make windows users having very strange segfaults. Simply because it was too large to be on the stack in such context and was screwing memory ! --- exercises/functions/Structs.cpp | 1 - exercises/functions/Structs.h | 1 - 2 files changed, 2 deletions(-) diff --git a/exercises/functions/Structs.cpp b/exercises/functions/Structs.cpp index 979136d9..bf312925 100644 --- a/exercises/functions/Structs.cpp +++ b/exercises/functions/Structs.cpp @@ -16,5 +16,4 @@ SlowToCopy::SlowToCopy(const SlowToCopy& other) { std::cout << __func__ << ": Please don't copy me. This is slow.\n"; std::this_thread::sleep_for(std::chrono::seconds(3)); name = other.name; - std::memcpy(bigdata, other.bigdata, sizeof(bigdata)); } diff --git a/exercises/functions/Structs.h b/exercises/functions/Structs.h index be0c9b38..2497855d 100644 --- a/exercises/functions/Structs.h +++ b/exercises/functions/Structs.h @@ -8,7 +8,6 @@ struct FastToCopy { struct SlowToCopy { std::string name; - int bigdata[1000000]; // Functions to create and copy this struct. // We go into details on the next days. From c3f053a2929c83a9fa8ee2d66fd7916ca778110d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Sep 2023 03:46:03 +0000 Subject: [PATCH 041/156] Bump xu-cheng/latex-action from 2 to 3 Bumps [xu-cheng/latex-action](https://github.com/xu-cheng/latex-action) from 2 to 3. - [Release notes](https://github.com/xu-cheng/latex-action/releases) - [Commits](https://github.com/xu-cheng/latex-action/compare/v2...v3) --- updated-dependencies: - dependency-name: xu-cheng/latex-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build-slides.yml | 4 ++-- .github/workflows/publish-slides.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-slides.yml b/.github/workflows/build-slides.yml index abcb3fb3..8c77892d 100644 --- a/.github/workflows/build-slides.yml +++ b/.github/workflows/build-slides.yml @@ -23,7 +23,7 @@ jobs: - name: Set up Git repository uses: actions/checkout@v3 - name: Compile essentials - uses: xu-cheng/latex-action@v2 + uses: xu-cheng/latex-action@v3 if: matrix.version == 'essentials' with: root_file: C++Course.tex @@ -32,7 +32,7 @@ jobs: working_directory: talk extra_system_packages: "py-pygments" - name: Compile full course - uses: xu-cheng/latex-action@v2 + uses: xu-cheng/latex-action@v3 if: matrix.version == 'full' with: root_file: C++Course.tex diff --git a/.github/workflows/publish-slides.yml b/.github/workflows/publish-slides.yml index a1e28189..7e90f757 100644 --- a/.github/workflows/publish-slides.yml +++ b/.github/workflows/publish-slides.yml @@ -18,7 +18,7 @@ jobs: if: matrix.version == 'essentials' run: echo '\basictrue' > talk/onlybasics.tex - name: Compile LaTeX document - uses: xu-cheng/latex-action@v2 + uses: xu-cheng/latex-action@v3 with: root_file: C++Course.tex latexmk_use_xelatex: true From c9dafc0ab9459cb01cd40d792cf14d2b353a2724 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 03:52:42 +0000 Subject: [PATCH 042/156] Bump actions/checkout from 3 to 4 Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build-exercises.yml | 2 +- .github/workflows/build-slides.yml | 2 +- .github/workflows/publish-slides.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-exercises.yml b/.github/workflows/build-exercises.yml index 87127501..42ef554c 100644 --- a/.github/workflows/build-exercises.yml +++ b/.github/workflows/build-exercises.yml @@ -97,7 +97,7 @@ jobs: # The build/test steps to execute. steps: # Use a standard checkout of the code. - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # Run the CMake configuration. - name: CMake Configure run: cmake -S ${{ github.workspace }}/exercises/${{ matrix.EXERCISE.NAME }} diff --git a/.github/workflows/build-slides.yml b/.github/workflows/build-slides.yml index 8c77892d..d695b4b2 100644 --- a/.github/workflows/build-slides.yml +++ b/.github/workflows/build-slides.yml @@ -21,7 +21,7 @@ jobs: version: [ essentials, full ] steps: - name: Set up Git repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Compile essentials uses: xu-cheng/latex-action@v3 if: matrix.version == 'essentials' diff --git a/.github/workflows/publish-slides.yml b/.github/workflows/publish-slides.yml index 7e90f757..62483d46 100644 --- a/.github/workflows/publish-slides.yml +++ b/.github/workflows/publish-slides.yml @@ -13,7 +13,7 @@ jobs: matrix: version: [ essentials, full ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup essentials course if: matrix.version == 'essentials' run: echo '\basictrue' > talk/onlybasics.tex From bcd438f3846d0f8792b4766067a7198ffb45cd62 Mon Sep 17 00:00:00 2001 From: Bernhard Manfred Gruber Date: Tue, 12 Sep 2023 15:15:02 +0200 Subject: [PATCH 043/156] Update module implementation status and fix errors Fixes: #487 Co-authored-by: Stephan Hageboeck --- talk/expert/modules.tex | 202 ++++++++++++++++++++++------------------ 1 file changed, 112 insertions(+), 90 deletions(-) diff --git a/talk/expert/modules.tex b/talk/expert/modules.tex index 56dddd65..ca50e4f3 100644 --- a/talk/expert/modules.tex +++ b/talk/expert/modules.tex @@ -9,7 +9,7 @@ \begin{itemize} \item Better isolation. No cross-talk between multiple pieces of included code, and also not between included code and your code. \item Better control over public interface of your library. Avoid leaking library dependencies into user code. - \item Faster compilation + \item Faster compilation (\href{https://youtu.be/DJTEUFRslbI?si=ZRvH1wx0sVJVriLh&t=3259}{import fmt; \textgreater1500x faster}) \end{itemize} \end{itemize} \end{block} @@ -121,12 +121,12 @@ import math; import ; int main() { - Ratio r = golden(); // error (Ratio not visible) - auto r = golden(); // ok: (Ratio is reachable) - std::cout << r.num; // ok: members of reachable - // class types become visible + Ratio r = golden(); // error: Ratio not visible + auto r = golden(); // OK: Ratio is reachable + std::cout << r.num; // OK: members of reachable + // types are visible using R = decltype(r); - R r2{1.f, 3.f}; // ok + R r2{1.f, 3.f}; // OK } \end{cppcode*} \end{exampleblock} @@ -135,20 +135,24 @@ \begin{frame}[fragile] \frametitlecpp[20]{Module structure} \begin{exampleblock}{} + \small \begin{cppcode*}{gobble=2} - module; - #include // global module fragment - // ... // only preprocessor - // statements allowed - - export module math; // exported module name - - import ; // module preamble - // ... // only imports allowed - - export struct S { ... }; // module purview - export S f() { ... } // starts at first - std::string h() { ... } // non-import + module; // global module fragment (opt.) + #include // only preprocessor + // ... // statements allowed + + export module math; // module preamble starts with + // exported module name. + import ; // only imports allowed + // ... // + + export struct S { ... }; // module purview started + export S f(); // at first non-import + std::string h() { ... } + + module :private // private module fragment (opt.) + S f() { ... } // changes here trigger + // no recompilation of BMI \end{cppcode*} \end{exampleblock} \end{frame} @@ -206,10 +210,64 @@ \end{exampleblock} \end{frame} +\begin{frame}[fragile,shrink=5] + \frametitlecpp[20]{Submodules and re-exporting} + \begin{block}{} + Modules can (re-)export other modules using \cppinline{export import}: + \end{block} + \vspace{-5mm} + \begin{columns}[t] + \begin{column}{.45\textwidth} + \begin{exampleblock}{Module one} + \begin{cppcode*}{gobble=6} + export module one; + + export struct S { ... }; + \end{cppcode*} + \end{exampleblock} + \end{column} + \begin{column}{.45\textwidth} + \begin{exampleblock}{Module two} + \begin{cppcode*}{gobble=6} + export module two; + import ; + + export std::string b() + { ... } + \end{cppcode*} + \end{exampleblock} + \end{column} + \end{columns} + \begin{columns}[t] + \begin{column}{.45\textwidth} + \begin{exampleblock}{Module three} + \begin{cppcode*}{gobble=6} + export module three; + import one; + export import two; + + export S f() { ... } + \end{cppcode*} + \end{exampleblock} + \end{column} + \begin{column}{.45\textwidth} + \begin{exampleblock}{Module four} + \begin{cppcode*}{gobble=6} + export module four; + import three; + // b and f visible + // S and std::string only + // reachable + \end{cppcode*} + \end{exampleblock} + \end{column} + \end{columns} +\end{frame} + \begin{frame}[fragile,shrink=5] \frametitlecpp[20]{Module partitions} \begin{block}{} - We can split a module's interface into multiple files: + We can split a module's \emph{interface} into multiple files: \end{block} \vspace{-5mm} \begin{columns}[t] @@ -248,7 +306,7 @@ \begin{frame}[fragile,shrink=5] \frametitlecpp[20]{Module implementation units} \begin{block}{} - We can split a module's implementation into multiple files: + We can split a module's \emph{implementation} into multiple files: \end{block} \begin{exampleblock}{Interface} \begin{cppcode*}{gobble=2} @@ -285,57 +343,6 @@ \end{columns} \end{frame} -\begin{frame}[fragile,shrink=5] - \frametitlecpp[20]{Submodules and re-exporting} - \begin{block}{} - Modules can (re-)export other modules: - \end{block} - \vspace{-5mm} - \begin{columns}[t] - \begin{column}{.45\textwidth} - \begin{exampleblock}{Module base} - \begin{cppcode*}{gobble=6} - export module base; - - export struct S { ... }; - \end{cppcode*} - \end{exampleblock} - \end{column} - \begin{column}{.45\textwidth} - \begin{exampleblock}{Module bar} - \begin{cppcode*}{gobble=6} - export module bar; - import ; - - export std::string b() - { ... } - \end{cppcode*} - \end{exampleblock} - \end{column} - \end{columns} - \begin{columns}[t] - \begin{column}{.45\textwidth} - \begin{exampleblock}{Module foo} - \begin{cppcode*}{gobble=6} - export module foo; - import export module base; - import bar; - - export S f() { ... } - \end{cppcode*} - \end{exampleblock} - \end{column} - \begin{column}{.45\textwidth} - \begin{exampleblock}{Module math} - \begin{cppcode*}{gobble=6} - export module math; - export import foo; - \end{cppcode*} - \end{exampleblock} - \end{column} - \end{columns} -\end{frame} - \begin{frame}[fragile] \frametitlecpp[23]{Standard library modules} % see: Minimal module support for the standard library http://wg21.link/P2412 @@ -343,7 +350,7 @@ \begin{itemize} \item Use \cppinline|import std;| for the entire C++ standard library. Basically everything in namespace \cppinline|std|. \begin{itemize} - \item E.g.\ \cppinline{memcpy(a, b, n);}, \cppinline{sqrt(val);}, \cppinline{uint32_t i;} will not compile. You need to prefix \cppinline{std::}. + \item E.g.\ \cppinline{memcpy(a, b, n)}, \cppinline{sqrt(val)}, \cppinline{uint32_t i} will not compile. You need to prefix \cppinline{std::}. \end{itemize} \item Use \cppinline|import std.compat;| for the entire C and C++ standard library \item No macros are exported. For these, you still need to include the corresponding headers. @@ -525,7 +532,7 @@ very thick ] \draw [-Latex](7,10) -- (7,0) node [midway,right] {t}; - \draw[thick] node at(3, 10) [fill=white,rounded rectangle] {build dependencies}; + \draw[thick] node at(3, 10) [fill=white,rounded rectangle] {scan dependencies}; \path[thick] node (vec) at(5,9) [rectangle,draw] {\textless{}vector\textgreater{}} node (vecbmi) at(4,7.5) [rectangle,draw] {vector.bmi} @@ -572,16 +579,22 @@ \item Translation units no longer independent \begin{itemize} \item Extra tool needs to infer dependency graph before building - \item This graph needs to be communicated to the build system - \item We will likely need a \href{https://wg21.link/P1689}{standard dependency file format} + \begin{itemize} + \item Called a ``dependency scanner'' + \item Needs to be communicated to the build system + \item Using a new \href{https://wg21.link/P1689}{standard dependency file format} + \end{itemize} \item Parallel and distributed builds need synchronization \end{itemize} - \item Compilation of module translation units produces binary module interface (BMI) and object file + \item Compilation of module translation units produces a binary module interface (BMI) \emph{and} an object file \begin{itemize} - \item BMIs need to be maintained/shared between multiple compiler instances + \item Need to manage BMIs between multiple compiler invocations \end{itemize} - \item Tools beside the compiler need to build/read binary module interface (static analysis, auto completion, etc.) - \item The C++ standard specifies very little on how this works + \item Tools beside the compiler need to build/read BMIs + \begin{itemize} + \item E.g.\ static analysis, language servers for auto completion, etc. + \end{itemize} + \item The \cpp standard specifies very little on how this works \begin{itemize} \item We may experience large implementation divergence \end{itemize} @@ -593,12 +606,16 @@ \frametitlecpp[20]{Build system} \begin{block}{Status} \begin{itemize} - \item build2 supports everything g++ does - \item MSBuild figures out dependencies and build order automatically (Windows/Visual Studio only) + \item Dependency scanner since clang 16: \texttt{clang-scan-deps} + \item Experimental module support in cmake since 3.26, uses \texttt{clang-scan-deps}, many fixes in later versions % see: https://discourse.cmake.org/t/c-20-modules-update/7330/24 and https://youtu.be/c563KgO-uf4?si=HUpnSivtDxvBoTr3&t=3592 + \item MSBuild (Windows) fully handles dependency scanning \item \cppinline{g++ a.cpp b.cpp ...} ``just works'', must be one line though - \item GCC uses a \href{https://wg21.link/P1184}{module mapper} to resolve imports, which specifies a protocol and uses a central server for module maintenance \item \href{https://wg21.link/p1602}{Experimental extensions to GNU make} exist to grow dependency graph on the fly while modules are discovered - \item No support in cmake (3.23) yet + \item Header units unsupported in all build systems (May 2023) % See talk: https://youtu.be/_LGR0U5Opdg?si=yQoCYD2yGFhi_vs6&t=3768 + \item C++23: \cppinline{import std;} supported in MSVC, partially in clang + \begin{itemize} + \item GCC/clang/MSVC also plan support in C++20 % see: https://github.com/microsoft/STL/issues/3945 + \end{itemize} \end{itemize} \end{block} \end{frame} @@ -607,7 +624,9 @@ \frametitlecpp[20]{Building modules (g++)} \begin{block}{Case study: g++} \begin{itemize} - \item By default, g++ caches compiled module interfaces (CMI, i.e.\ BMI) in subdirectory \texttt{./gcm.cache} + \item BMI is called CMI (compiled module interfaces) + \item By default, g++ caches CMIs in subdirectory \texttt{./gcm.cache} + \item Uses a \href{https://wg21.link/P1184}{module mapper} to resolve imports, which specifies a protocol and uses a central server for module maintenance \item Each module needs to be built before it can be imported \begin{itemize} \item {\footnotesize \cppinline{g++ -std=c++20 -fmodules-ts -c ratio.cpp -o ratio.o}} @@ -630,16 +649,17 @@ \begin{itemize} \item Start writing importable headers (no macro dependencies) \begin{itemize} - \item This allows dual use: \cppinline{#include} before \cpp20 and \cppinline{import} with \cpp20 + \item Dual use: \cppinline{#include} before \cpp20 and \cppinline{import} with \cpp20 \end{itemize} \item Watch progress on module support in your build system \end{itemize} \end{exampleblock} \begin{exampleblock}{Guidance for tomorrow} \begin{itemize} - \item Start importing headers when \cpp20 is available - \item Start writing modules when all users of your code have \cpp20 - \item Start using \cppinline{import std;} when \cpp23 is available + \item Start writing modules when your users have \cpp20 + \item Maybe import standard headers when \cpp20 is available + \item Start using \cppinline{import std;} when available + \item Future of header units unclear (implementation difficulties) \end{itemize} \end{exampleblock} \end{frame} @@ -647,10 +667,12 @@ \begin{frame}[fragile] \frametitlecpp[20]{Modules} \begin{block}{Resources} + \small \begin{itemize} - \item \href{https://www.youtube.com/watch?v=szHV6RdQdg8}{Practical C++ Modules - Boris Kolpackov - CppCon 2019} \item \href{https://www.youtube.com/watch?v=nP8QcvPpGeM}{A (Short) Tour of C++ Modules - Daniela Engert - CppCon 2021} (very technical) \item Understanding C++ Modules: \href{https://vector-of-bool.github.io/2019/03/10/modules-1.html}{Part1}, \href{https://vector-of-bool.github.io/2019/03/31/modules-2.html}{Part2} and \href{https://vector-of-bool.github.io/2019/10/07/modules-3.html}{Part3}. + \item \href{https://www.youtube.com/watch?v=DJTEUFRslbI}{So, You Want to Use C++ Modules … Cross-Platform? - Daniela Engert - C++ on Sea 2023} + \item \href{https://www.youtube.com/watch?v=c563KgO-uf4&t=686s}{import CMake: 2023 State of C++20 modules in CMake - Bill Hoffman - CppNow 2023} \end{itemize} \end{block} \end{frame} From 63ad561e6141914f86d60bcc5285f2cef501be0b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 3 Oct 2023 08:10:07 +0000 Subject: [PATCH 044/156] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/codespell-project/codespell: v2.2.5 → v2.2.6](https://github.com/codespell-project/codespell/compare/v2.2.5...v2.2.6) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 07803899..a729c54d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/codespell-project/codespell - rev: 'v2.2.5' + rev: 'v2.2.6' hooks: - id: codespell args: ["-I", "codespell.txt"] From 9f4ca2eeaf2bc2549f4541705b40c4a3fe501432 Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Wed, 11 Oct 2023 14:05:18 +0200 Subject: [PATCH 045/156] Tiny fixes found while preparing next session of the advanced course --- talk/C++Course.tex | 2 +- talk/basicconcepts/assert.tex | 6 +++--- talk/basicconcepts/coresyntax.tex | 6 +++--- talk/morelanguage/copyelision.tex | 2 +- talk/morelanguage/morestl.tex | 2 +- talk/objectorientation/typecasting.tex | 8 +++----- 6 files changed, 12 insertions(+), 14 deletions(-) diff --git a/talk/C++Course.tex b/talk/C++Course.tex index a1fb6c00..bb06acbc 100644 --- a/talk/C++Course.tex +++ b/talk/C++Course.tex @@ -147,7 +147,7 @@ \input{objectorientation/adl} \end{advanced} -\section[More]{Core modern \cpp} +\section[Core]{Core modern \cpp} \input{morelanguage/constness} \begin{advanced} \input{morelanguage/constexpr} diff --git a/talk/basicconcepts/assert.tex b/talk/basicconcepts/assert.tex index 5ad4cbc4..6911443c 100644 --- a/talk/basicconcepts/assert.tex +++ b/talk/basicconcepts/assert.tex @@ -77,7 +77,7 @@ \begin{cppcode*}{} double f(UserType a) { static_assert( - std::is_floating_point::value, + std::is_floating_point_v, // C++17 "This function expects floating-point types."); return std::sqrt(a); } @@ -89,7 +89,7 @@ \textcolor{blue}{a.cpp:3:9:} \textcolor{red}{error:} \textcolor{blue}{static assertion failed: This function} \textcolor{blue}{expects floating-point types.} 2 | static_assert( - | \textcolor{red}{std::is_floating_point::value}, - | \textcolor{red}{~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~} + | \textcolor{red}{std::is_floating_point_v}, + | \textcolor{red}{~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~} \end{Verbatim} \end{frame} diff --git a/talk/basicconcepts/coresyntax.tex b/talk/basicconcepts/coresyntax.tex index 11362fad..13548059 100644 --- a/talk/basicconcepts/coresyntax.tex +++ b/talk/basicconcepts/coresyntax.tex @@ -173,12 +173,12 @@ #include // may define these: std::float16_t = 3.14f16; // 16 (1+5+10) bit float - std::float32_t = 3.14f32; // like float + std::float32_t = 3.14f32; // like float (1+8+23) // but different type - std::float64_t = 3.14f64; // like double + std::float64_t = 3.14f64; // like double (1+11+52) // but different type std::float128_t = 3.14f128; // 128 (1+15+112) bit float - std::bfloat_t = 3.14bf16; // 16 (1+8+7) bit float + std::bfloat16_t = 3.14bf16; // 16 (1+8+7) bit float // also F16, F32, F64, F128 or BF16 suffix possible \end{cppcode*} diff --git a/talk/morelanguage/copyelision.tex b/talk/morelanguage/copyelision.tex index adf5bd98..e5fd1917 100644 --- a/talk/morelanguage/copyelision.tex +++ b/talk/morelanguage/copyelision.tex @@ -2,7 +2,7 @@ \begin{frame}[fragile] \frametitlecpp[17]{Copy elision} - \begin{block}{Copy elision} + \begin{block}{Where does it take place ?} \small \begin{cppcode*}{} struct Foo { ... }; diff --git a/talk/morelanguage/morestl.tex b/talk/morelanguage/morestl.tex index 561143fe..e8ee92f5 100644 --- a/talk/morelanguage/morestl.tex +++ b/talk/morelanguage/morestl.tex @@ -99,7 +99,7 @@ \begin{cppcode*}{} std::optional parse_phone(std::string_view in) { if (is_valid_phone(in)) - return in; // equiv. to optional{in}; + return in; // equiv. to optional{in}; return {}; // or: return std::nullopt; (empty opt.) } if (v) { // or: v.is_valid() diff --git a/talk/objectorientation/typecasting.tex b/talk/objectorientation/typecasting.tex index ede5176f..5b45887f 100644 --- a/talk/objectorientation/typecasting.tex +++ b/talk/objectorientation/typecasting.tex @@ -23,7 +23,7 @@ \begin{frame}[fragile] \frametitlecpp[98]{Type casting example} \small - \begin{exampleblock}{} + \begin{exampleblockGB}{Practically}{https://godbolt.org/z/16faqc64s}{\texttt{casting}} \begin{cppcode*}{gobble=2} struct A{ virtual ~A()=default; } a; struct B : A {} b; @@ -34,9 +34,7 @@ B& f = dynamic_cast(c); // OK, c is a B B& g = dynamic_cast(a); // throws std::bad_cast - B& foo(A& h) { - return dynamic_cast(h); - } + B& foo(A& h) { return dynamic_cast(h); } B& i = foo(c); // OK, c is a B B* j = dynamic_cast(&a); // nullptr. a not a B. @@ -44,7 +42,7 @@ // Will not reach this } \end{cppcode*} - \end{exampleblock} + \end{exampleblockGB} \end{frame} \begin{frame}[fragile] From bc7e723f8da648915fd6975963e77868940645f3 Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Wed, 11 Oct 2023 14:06:32 +0200 Subject: [PATCH 046/156] Added on slide on std::expected --- talk/morelanguage/morestl.tex | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/talk/morelanguage/morestl.tex b/talk/morelanguage/morestl.tex index e8ee92f5..ea882a6b 100644 --- a/talk/morelanguage/morestl.tex +++ b/talk/morelanguage/morestl.tex @@ -147,6 +147,35 @@ \end{exerciseWithShortcut} \end{frame} +\begin{frame}[fragile] + \frametitlecpp[23]{std::expected \cpprefLink{https://en.cppreference.com/w/cpp/utility/expected}} + \begin{block}{Manages either of 2 values (expected or not)} + \begin{itemize} + \item templated by the 2 value types + \item Useful for the return value of a function that may fail + \begin{itemize} + \item and would then return another type (error type) + \end{itemize} + \end{itemize} + \end{block} + \begin{exampleblock}{} + \small + \begin{cppcode*}{} + enum class Error {...}; + std::expected parse(std::string_view in) { + if (is_valid(in)) return convert_to_int(in); + return std::unexpected(Error::...); + } + auto v = parse(...); + if (v.has_value()) { + std::cout << *v; // (unchecked) + foo(v.value()); // may throw bad_expected_access + } else + log(v.error()); + \end{cppcode*} + \end{exampleblock} +\end{frame} + \begin{frame}[fragile] \frametitlecpp[17]{std::variant \cpprefLink{https://en.cppreference.com/w/cpp/utility/variant}} \begin{block}{A type-safe union} From 4c7fe95a50cecb8d7cc005c026e240f86e4ac977 Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Fri, 13 Oct 2023 16:40:44 +0200 Subject: [PATCH 047/156] Last tiny fixes for autumn 24 session of the course --- talk/concurrency/mutexes.tex | 12 +++++++++--- talk/expert/modules.tex | 5 +++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/talk/concurrency/mutexes.tex b/talk/concurrency/mutexes.tex index 6a118d9e..b2d96d9e 100644 --- a/talk/concurrency/mutexes.tex +++ b/talk/concurrency/mutexes.tex @@ -114,9 +114,15 @@ \frametitlecpp[17]{Mutexes and Locks} \begin{goodpractice}{Locking} \begin{itemize} - \item Generally, use \cppinline{std::scoped_lock}. Before \cpp17 use \cppinline{std::lock_guard}. - \item Hold as short as possible, consider wrapping critical section in block statement \cppinline|{ }| - \item Only if manual control needed, use \cppinline{std::unique_lock} + \item Generally, use \cppinline{std::scoped_lock} + \begin{itemize} + \item Before \cpp17 use \cppinline{std::lock_guard}. + \end{itemize} + \item Hold as short as possible + \begin{itemize} + \item Consider wrapping critical section in block statement \cppinline|{ }| + \end{itemize} + \item Only if manual control needed, use \cppinline{std::unique_lock} \end{itemize} \end{goodpractice} \begin{exampleblock}{} diff --git a/talk/expert/modules.tex b/talk/expert/modules.tex index ca50e4f3..29021119 100644 --- a/talk/expert/modules.tex +++ b/talk/expert/modules.tex @@ -7,7 +7,7 @@ \item Modules allow for sharing declarations and definitions across translation units \item Header files do the same, but modules have benefits: \begin{itemize} - \item Better isolation. No cross-talk between multiple pieces of included code, and also not between included code and your code. + \item Better isolation. No cross-talk between multiple pieces of included code, or between included code and your code. \item Better control over public interface of your library. Avoid leaking library dependencies into user code. \item Faster compilation (\href{https://youtu.be/DJTEUFRslbI?si=ZRvH1wx0sVJVriLh&t=3259}{import fmt; \textgreater1500x faster}) \end{itemize} @@ -350,7 +350,8 @@ \begin{itemize} \item Use \cppinline|import std;| for the entire C++ standard library. Basically everything in namespace \cppinline|std|. \begin{itemize} - \item E.g.\ \cppinline{memcpy(a, b, n)}, \cppinline{sqrt(val)}, \cppinline{uint32_t i} will not compile. You need to prefix \cppinline{std::}. + \item E.g.\ \cppinline{memcpy(a, b, n)}, \cppinline{sqrt(val)}, \cppinline{uint32_t} + \item Note that you need to prefix with \cppinline{std::} \end{itemize} \item Use \cppinline|import std.compat;| for the entire C and C++ standard library \item No macros are exported. For these, you still need to include the corresponding headers. From 0bf049cc3572b64b71bbfff18be0898f016a4c3c Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Fri, 13 Oct 2023 19:00:15 +0200 Subject: [PATCH 048/156] Fixes in tables of godbolt and good practice links (#496) Fixes in tables of godbolt and good practice links --------- Co-authored-by: Sebastien Ponce Co-authored-by: Bernhard Manfred Gruber --- talk/expert/coroutines.tex | 2 +- talk/morelanguage/raii.tex | 4 ++-- talk/objectorientation/advancedoo.tex | 5 ++--- talk/objectorientation/constructors.tex | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/talk/expert/coroutines.tex b/talk/expert/coroutines.tex index 0146a6d0..23004099 100644 --- a/talk/expert/coroutines.tex +++ b/talk/expert/coroutines.tex @@ -234,7 +234,7 @@ \subsection{Coroutines} \begin{frame}[fragile] \frametitlecpp[20]{Resuming a coroutine} \scriptsize - \begin{exampleblockGB}{User code}{https://godbolt.org/z/qx46Pa4v3}{Resuming a coroutine} + \begin{exampleblockGB}{User code}{https://godbolt.org/z/qx46Pa4v3}{Coroutine resumption} \begin{cppcode*}{gobble=2} Task myCoroutine() { std::cout << "Step 1 of coroutine\n"; diff --git a/talk/morelanguage/raii.tex b/talk/morelanguage/raii.tex index 3f0d358e..55d7654d 100644 --- a/talk/morelanguage/raii.tex +++ b/talk/morelanguage/raii.tex @@ -335,7 +335,7 @@ \begin{frame}[fragile] \frametitlecpp[11]{Quiz: \texttt{std::shared\_ptr} in use} - \begin{exampleblockGB}{What is the output of this code?}{https://godbolt.org/z/vM35Y6qEW}{\texttt{std::shared\_ptr} quiz} + \begin{exampleblockGB}{What is the output of this code?}{https://godbolt.org/z/vM35Y6qEW}{\texttt{shared\_ptr} quiz} \small \begin{cppcode*}{gobble=2} auto shared = std::make_shared(100); @@ -397,7 +397,7 @@ \begin{frame}[fragile] \frametitlecpp[11]{Quiz: \texttt{shared\_ptr} and \texttt{weak\_ptr} in use} - \begin{exampleblockGB}{What is the output of this code?}{https://godbolt.org}{\texttt{shared\_ptr} vs.\ \texttt{weak\_ptr} quiz} + \begin{exampleblockGB}{What is the output of this code?}{https://godbolt.org}{\texttt{shared/weak\_ptr}} \small \begin{cppcode*}{gobble=2} auto shared = std::make_shared(100); diff --git a/talk/objectorientation/advancedoo.tex b/talk/objectorientation/advancedoo.tex index 149caeaf..621d455b 100644 --- a/talk/objectorientation/advancedoo.tex +++ b/talk/objectorientation/advancedoo.tex @@ -536,13 +536,12 @@ \item And for rare special cases \end{itemize} \end{goodpractice} - \pause - \begin{goodpractice}{Absolutely avoid diamond-shaped inheritance} + \begin{goodpracticeWithShortcut}{Absolutely avoid diamond-shaped inheritance}{NO diamond inheritance} \begin{itemize} \item This is a sign that your architecture is not correct \item In case you are tempted, think twice and change your mind \end{itemize} - \end{goodpractice} + \end{goodpracticeWithShortcut} \end{frame} \begin{frame}[fragile] diff --git a/talk/objectorientation/constructors.tex b/talk/objectorientation/constructors.tex index 6edcc0ad..fb2fbf6e 100644 --- a/talk/objectorientation/constructors.tex +++ b/talk/objectorientation/constructors.tex @@ -133,7 +133,7 @@ \item A constructor with a single non-default parameter can be used by the compiler for an implicit conversion. \end{itemize} \end{block} - \begin{exampleblockGB}{Example}{https://godbolt.org/z/TvqT185fz}{Unary constructor in action} + \begin{exampleblockGB}{Example}{https://godbolt.org/z/TvqT185fz}{Unary constructor} \begin{cppcode} void print(const Vector & v) { std::cout << "printing v elements...\n"; From 91ca7b51646dd0834204508aa3fe436ec594e009 Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Mon, 16 Oct 2023 14:47:44 +0200 Subject: [PATCH 049/156] Fixes to exercises after advanced session of Oct 2023 --- exercises/operators/operators.cpp | 4 ++-- exercises/operators/solution/operators.sol.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/exercises/operators/operators.cpp b/exercises/operators/operators.cpp index af4deb09..163da43e 100644 --- a/exercises/operators/operators.cpp +++ b/exercises/operators/operators.cpp @@ -13,7 +13,7 @@ class Fraction { m_denom /= gcd; } - int m_num, m_denom; + unsigned int m_num, m_denom; }; // TODO: operators @@ -55,7 +55,7 @@ int main() { printAndCheck("One third times two", f, Fraction{2, 3}); f *= athird; - printAndCheck("One third times one third", f, Fraction{2, 9}); + printAndCheck("Two third times one third", f, Fraction{2, 9}); // you might have some redundancy between the implementation of operator* and // operator*=. Can you refactor your code and implement operator* in terms of diff --git a/exercises/operators/solution/operators.sol.cpp b/exercises/operators/solution/operators.sol.cpp index eced479d..b8abd10e 100644 --- a/exercises/operators/solution/operators.sol.cpp +++ b/exercises/operators/solution/operators.sol.cpp @@ -46,12 +46,12 @@ class Fraction { private: void normalize() { - const int gcd = std::gcd(m_num, m_denom); + auto const gcd = std::gcd(m_num, m_denom); m_num /= gcd; m_denom /= gcd; } - int m_num, m_denom; + unsigned int m_num, m_denom; }; void printAndCheck(std::string const & what, Fraction const & result, Fraction const & expected) { @@ -90,7 +90,7 @@ int main() { printAndCheck("One third times two", f, Fraction{2, 3}); f *= athird; - printAndCheck("One third times one third", f, Fraction{2, 9}); + printAndCheck("Two third times one third", f, Fraction{2, 9}); // you might have some redundancy between the implementation of operator* and // operator*=. Can you refactor your code and implement operator* in terms of From 9c8abaee4a2c8ab736b3e665062e5a5c3e67c7c3 Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Mon, 16 Oct 2023 15:27:50 +0200 Subject: [PATCH 050/156] Fixes to ADL slide concerning the order of searches --- talk/objectorientation/adl.tex | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/talk/objectorientation/adl.tex b/talk/objectorientation/adl.tex index 24ab1186..b44161ac 100644 --- a/talk/objectorientation/adl.tex +++ b/talk/objectorientation/adl.tex @@ -19,7 +19,10 @@ \begin{itemize} \item here for \cppinline{std} and \cppinline{operator<<} \item name is looked for in a sequence of scopes until found - \item remaining scopes are not examined + \begin{itemize} + \item remaining scopes are not examined + \end{itemize} + \item in parallel Argument Dependent Loopkup (ADL) may happen \end{itemize} \end{itemize} \end{block} @@ -32,11 +35,14 @@ \item file (only for global level usage) \item current namespace/block, enclosing namespaces/blocks, etc... \item current class if any, base classes if any, etc... - \item for a call expression (e.g.\ \cppinline{f(a, b)} or \cppinline{a + b}), Argument Dependent Lookup (ADL) \end{itemize} \end{block} \begin{exampleblock}{Argument Dependent Lookup (simplified)} - To find a function name (including operators), the compiler also examines the arguments. For each argument, it searches: + Only for call expression + \begin{itemize} + \item e.g.\ \cppinline{f(a, b)} or \cppinline{a + b} + \end{itemize} + The compiler also examines arguments one by one and searches: \begin{itemize} \item class, if any \item direct and indirect base classes, if any From 508712fbd924ff9e30bd4b8b63deffe3658f95b6 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Mon, 16 Oct 2023 09:23:27 +0200 Subject: [PATCH 051/156] Mark slide on fixed-size integer types as C++11. std::intptr_t is not in C++98, so it makes sense to promote the slide. --- talk/basicconcepts/coresyntax.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/talk/basicconcepts/coresyntax.tex b/talk/basicconcepts/coresyntax.tex index 13548059..60ca43bb 100644 --- a/talk/basicconcepts/coresyntax.tex +++ b/talk/basicconcepts/coresyntax.tex @@ -143,7 +143,7 @@ \begin{advanced} \begin{frame}[fragile] - \frametitlecpp[98]{Useful aliases} + \frametitlecpp[11]{Useful aliases} \begin{cppcode} #include // (and others) defines: From 7fe5ef9649f6ee997f3ef91ded13535449db0b2b Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Mon, 16 Oct 2023 09:35:53 +0200 Subject: [PATCH 052/156] Add a const to a range-based for loop. --- talk/basicconcepts/control.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/talk/basicconcepts/control.tex b/talk/basicconcepts/control.tex index 7e83b449..42e7e43a 100644 --- a/talk/basicconcepts/control.tex +++ b/talk/basicconcepts/control.tex @@ -240,7 +240,7 @@ \end{alertblock} \begin{exampleblock}{\cpp20} \begin{cppcode*}{firstnumber=6} - for (std::size_t i = 0; auto& d : data) { + for (std::size_t i = 0; auto const & d : data) { std::cout << i++ << ' ' << d << '\n'; } \end{cppcode*} From 8634921d3f13e2927f366adec7a84a949e73d524 Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Wed, 18 Oct 2023 10:15:56 +0200 Subject: [PATCH 053/156] Small fixes from Oct 23 session of the course --- talk/morelanguage/morestl.tex | 15 ++++++++------- talk/morelanguage/templates.tex | 24 +++++++++++++----------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/talk/morelanguage/morestl.tex b/talk/morelanguage/morestl.tex index ea882a6b..92cccacb 100644 --- a/talk/morelanguage/morestl.tex +++ b/talk/morelanguage/morestl.tex @@ -56,7 +56,7 @@ \begin{frame}[fragile] \frametitlecpp[20]{\texttt{std::span} - Usage} - \begin{exampleblockGB}{Some example}{https://godbolt.org/z/W81sjrbxK}{\texttt{span}} + \begin{exampleblockGB}{Some example}{https://godbolt.org/z/bTWjM8ba1}{\texttt{span}} \scriptsize \begin{cppcode*}{} void print(std::span c) { @@ -102,7 +102,7 @@ return in; // equiv. to optional{in}; return {}; // or: return std::nullopt; (empty opt.) } - if (v) { // or: v.is_valid() + if (v) { // or: v.has_value() process_phone(v.value()); // or: *v (unchecked) v->call(); // calls Phone::call() (unchecked) } @@ -158,7 +158,7 @@ \end{itemize} \end{itemize} \end{block} - \begin{exampleblock}{} + \begin{exampleblockGB}{Practically}{https://godbolt.org/z/9rjn1hzeW}{\texttt{expected}} \small \begin{cppcode*}{} enum class Error {...}; @@ -167,13 +167,13 @@ return std::unexpected(Error::...); } auto v = parse(...); - if (v.has_value()) { + if (v) { // or v.has_value() std::cout << *v; // (unchecked) foo(v.value()); // may throw bad_expected_access } else log(v.error()); \end{cppcode*} - \end{exampleblock} + \end{exampleblockGB} \end{frame} \begin{frame}[fragile] @@ -378,7 +378,8 @@ \item CV qualifiers and references allowed \end{itemize} \end{block} - \begin{exampleblock}{} + \begin{exampleblockGB}{Practically}{https://godbolt.org/z/PfWzxjP7W}{\texttt{Structured binding}} + \small \begin{cppcode*}{} std::tuple tuple = ...; auto [ a, b, c ] = tuple; @@ -392,7 +393,7 @@ std::unordered_map map = ...; for (const auto& [key, value] : map) { ... } \end{cppcode*} - \end{exampleblock} + \end{exampleblockGB} \end{frame} \begin{frame}[fragile] diff --git a/talk/morelanguage/templates.tex b/talk/morelanguage/templates.tex index f241359a..a8eca9c0 100644 --- a/talk/morelanguage/templates.tex +++ b/talk/morelanguage/templates.tex @@ -420,17 +420,19 @@ \item Since \cpp20: CTAD for aggregates (no constructor needed) \end{itemize} \end{block} - \begin{cppcode*}{} - template - struct Triple { - Triple(A a, B b, C c) : a(a), b(b), c(c) {} // C++17 - A a; B b; C c; - }; - - Triple t{42, true, 3.14}; // Triple - Triple t{42, true, 3.14}; // compilation error - Triple t{42, true, 3.14}; // not CTAD - \end{cppcode*} + \begin{exampleblockGB}{Practically}{https://godbolt.org/z/eYhsMcGsW}{CTAD} + \small + \begin{cppcode*}{} + template + struct Triple { + Triple(A a, B b, C c) : a(a), b(b), c(c) {} + A a; B b; C c; + }; + Triple t{42, true, 3.14}; // Triple + Triple t2{42, true, 3.14}; // compilation error + Triple t3{42, true, 3.14}; // not CTAD + \end{cppcode*} + \end{exampleblockGB} \end{frame} \begin{frame}[fragile] From 571b224d1b1cb065a35c7ba845022deab3fa3717 Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Wed, 18 Oct 2023 11:37:00 +0200 Subject: [PATCH 054/156] Moved if constexpr to constexpr part and out of STL --- talk/morelanguage/constexpr.tex | 27 +++++++++++++++++++++++++++ talk/morelanguage/morestl.tex | 27 --------------------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/talk/morelanguage/constexpr.tex b/talk/morelanguage/constexpr.tex index 604fb0f0..de68449e 100644 --- a/talk/morelanguage/constexpr.tex +++ b/talk/morelanguage/constexpr.tex @@ -121,6 +121,33 @@ \end{cppcode*} \end{frame} +\begin{frame}[fragile] + \frametitlecpp[17]{compile-time branches} + \begin{block}{{\it if constexpr}} + \begin{itemize} + \item takes a \cppinline{constexpr} expression as condition + \item evaluates at compile time + \item key benefit: the discarded branch can contain invalid code + \end{itemize} + \end{block} + \begin{exampleblock}{Example code} + \small + \begin{cppcode*}{} + template + auto remove_ptr(T t) { + if constexpr (std::is_pointer_v) { + return *t; + } else { + return t; + } + } + int i = ...; int *j = ...; + int r = remove_ptr(i); // equivalent to i + int q = remove_ptr(j); // equivalent to *j + \end{cppcode*} + \end{exampleblock} +\end{frame} + \begin{frame}[fragile] \frametitlecpp[20]{Immediate functions} \begin{block}{Motivation} diff --git a/talk/morelanguage/morestl.tex b/talk/morelanguage/morestl.tex index 92cccacb..a407b975 100644 --- a/talk/morelanguage/morestl.tex +++ b/talk/morelanguage/morestl.tex @@ -424,30 +424,3 @@ \end{cppcode*} \end{exampleblock} \end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{compile-time branches} - \begin{block}{{\it if constexpr}} - \begin{itemize} - \item takes a \cppinline{constexpr} expression as condition - \item evaluates at compile time - \item key benefit: the discarded branch can contain invalid code - \end{itemize} - \end{block} - \begin{exampleblock}{Example code} - \small - \begin{cppcode*}{} - template - auto remove_ptr(T t) { - if constexpr (std::is_pointer_v) { - return *t; - } else { - return t; - } - } - int i = ...; int *j = ...; - int r = remove_ptr(i); // equivalent to i - int q = remove_ptr(j); // equivalent to *j - \end{cppcode*} - \end{exampleblock} -\end{frame} From 72837c90e64224d5cefca64e36e0033090f0419d Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Thu, 19 Oct 2023 14:32:17 +0200 Subject: [PATCH 055/156] Add a slide on osyncstream (cpp20). --- talk/concurrency/mutexes.tex | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/talk/concurrency/mutexes.tex b/talk/concurrency/mutexes.tex index b2d96d9e..b6bb3dd6 100644 --- a/talk/concurrency/mutexes.tex +++ b/talk/concurrency/mutexes.tex @@ -225,3 +225,25 @@ \end{cppcode*} \end{exampleblock} \end{frame} + +\begin{frame}[fragile] + \frametitlecpp[20]{Synchronised \texttt{cout}} + \begin{block}{Parallel writing to streams} + \begin{itemize} + \item All parallel writes to streams become garbled when not synchronised + \item \cppinline{std::osyncstream} is a wrapper to synchronise output to streams + \item Multiple instances of the osyncstream synchronise globally + \end{itemize} + \end{block} + \begin{exampleblock}{} + \begin{cppcode*}{gobble=2} + void worker(const int id, std::ostream & os); + void func() { + std::osyncstream synccout1{std::cout}; + std::osyncstream synccout2{std::cout}; + std::jthread t1{worker, 0, std::ref(synccout1)}; + std::jthread t2{worker, 1, std::ref(synccout2)}; + } + \end{cppcode*} + \end{exampleblock} +\end{frame} From 12ff3941ea78f95c984f8bf38b73ff58f06e8e0e Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Thu, 19 Oct 2023 14:32:50 +0200 Subject: [PATCH 056/156] Add godbolt example for std::async. --- talk/concurrency/threadsasync.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/talk/concurrency/threadsasync.tex b/talk/concurrency/threadsasync.tex index d80ee2fb..dabaf4ee 100644 --- a/talk/concurrency/threadsasync.tex +++ b/talk/concurrency/threadsasync.tex @@ -106,13 +106,13 @@ \end{itemize} \end{block} \pause - \begin{exampleblock}{Usage} + \begin{exampleblockGB}{Usage}{https://godbolt.org/z/oMGz5jhMr}{\texttt{std::async}} \begin{cppcode*}{} int f() {...} auto res1 = std::async(std::launch::async, f); auto res2 = std::async(std::launch::deferred, f); \end{cppcode*} - \end{exampleblock} + \end{exampleblockGB} \end{frame} \begin{frame}[fragile] From bb31a0c9a87a63a1320fa2735b023e4b491d5960 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Thu, 19 Oct 2023 14:33:13 +0200 Subject: [PATCH 057/156] Refine statement about leak sanitizer. LSAN is active by default in modern clang versions. --- talk/tools/sanitizers.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/talk/tools/sanitizers.tex b/talk/tools/sanitizers.tex index c3498445..fe43149d 100644 --- a/talk/tools/sanitizers.tex +++ b/talk/tools/sanitizers.tex @@ -153,7 +153,7 @@ \begin{block}{Finding memory leaks with ASan} \begin{itemize} \item On linux, ASan can display memory leaks - \item Start executable with \mintinline{bash}{ASAN_OPTIONS=detect_leaks=1 ./myProgram} + \item If not already running, start executable with \mintinline{bash}{ASAN_OPTIONS=detect_leaks=1 ./myProgram} \end{itemize} \end{block} \scriptsize From 4a5e7708545cf338f850a029301d2b58592ebff0 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Thu, 19 Oct 2023 14:33:13 +0200 Subject: [PATCH 058/156] Refine statement about leak sanitizer. LSAN is active by default in modern clang versions. --- talk/tools/sanitizers.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/talk/tools/sanitizers.tex b/talk/tools/sanitizers.tex index fe43149d..ef2f86f3 100644 --- a/talk/tools/sanitizers.tex +++ b/talk/tools/sanitizers.tex @@ -152,8 +152,8 @@ \column{\textwidth+1cm} \begin{block}{Finding memory leaks with ASan} \begin{itemize} - \item On linux, ASan can display memory leaks - \item If not already running, start executable with \mintinline{bash}{ASAN_OPTIONS=detect_leaks=1 ./myProgram} + \item On linux, ASan can display memory leaks (``LeakSanitizer'') + \item Might be active already, otherwise start executable with \mintinline{bash}{ASAN_OPTIONS=detect_leaks=1 ./myProgram} \end{itemize} \end{block} \scriptsize From c89fa2ad6cb9cba2773c51fb2720af83fb8fccc5 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 20 Oct 2023 15:23:01 +0200 Subject: [PATCH 059/156] Clarify that declval is a function. --- talk/expert/sfinae.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/talk/expert/sfinae.tex b/talk/expert/sfinae.tex index 7b3d66d5..4fd3c2ee 100644 --- a/talk/expert/sfinae.tex +++ b/talk/expert/sfinae.tex @@ -51,9 +51,9 @@ \frametitlecpp[11]{\texttt{declval}} \begin{block}{The main idea} \begin{itemize} - \item gives you a reference to a ``fake'' object at compile time + \item function to create reference to a ``fake'' object at compile time \item useful for types that cannot easily be constructed - \item use only in unevaluated contexts, e.g. inside \cppinline{decltype} + \item use only in unevaluated contexts, e.g.\ inside \cppinline{decltype} \end{itemize} \end{block} \begin{exampleblock}{} From e2007b974c38498acc4c2d1ac3aff9ec9485dd7e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 19:57:29 +0000 Subject: [PATCH 060/156] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v4.4.0 → v4.5.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.4.0...v4.5.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a729c54d..29b16151 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: check-added-large-files - id: check-case-conflict From fb420a37c1c81b17e0cd6ddb4ce9af518c5fbe42 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Dec 2023 16:19:31 -0500 Subject: [PATCH 061/156] Bump actions/upload-artifact from 3 to 4 (#505) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-slides.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-slides.yml b/.github/workflows/build-slides.yml index d695b4b2..47e78b98 100644 --- a/.github/workflows/build-slides.yml +++ b/.github/workflows/build-slides.yml @@ -41,7 +41,7 @@ jobs: working_directory: talk extra_system_packages: "py-pygments" - name: Upload PDF as artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: PDF_${{matrix.version}} path: | From 9541b92bad1d8d205f2767e86a90392ecd51c8e0 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Wed, 17 Jan 2024 16:35:10 +0100 Subject: [PATCH 062/156] Refactor goodpractice environment to take optional arguments. Using the optional argument, a shortened title can be passed like for the usual section or chapter commands. --- talk/setup.tex | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/talk/setup.tex b/talk/setup.tex index 34c4dafe..709dfdda 100644 --- a/talk/setup.tex +++ b/talk/setup.tex @@ -140,9 +140,11 @@ {% \end{beamerboxesrounded} } -\newenvironment{goodpractice}[1] +\newenvironment{goodpractice}[2][] {% - \begin{goodpracticeWithShortcut}{#1}{#1} + \ifthenelse{\equal{#1}{}}% + { \begin{goodpracticeWithShortcut}{#2}{#2} } + { \begin{goodpracticeWithShortcut}{#2}{#1} } }% {% \end{goodpracticeWithShortcut} From cdd02dcedbc8a355e4a7d266f913154e50f8f130 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Wed, 17 Jan 2024 17:12:13 +0100 Subject: [PATCH 063/156] [NFC] Replace all "goodpracticeWith.." by "goodpractice" environment. --- talk/basicconcepts/arrayspointers.tex | 8 ++++---- talk/basicconcepts/control.tex | 4 ++-- talk/basicconcepts/headersinterfaces.tex | 4 ++-- talk/morelanguage/raii.tex | 8 ++++---- talk/morelanguage/random.tex | 4 ++-- talk/morelanguage/stl.tex | 4 ++-- talk/objectorientation/advancedoo.tex | 4 ++-- talk/objectorientation/allocations.tex | 8 ++++---- talk/objectorientation/constructors.tex | 4 ++-- 9 files changed, 24 insertions(+), 24 deletions(-) diff --git a/talk/basicconcepts/arrayspointers.tex b/talk/basicconcepts/arrayspointers.tex index abbbd65a..5cc2d69b 100644 --- a/talk/basicconcepts/arrayspointers.tex +++ b/talk/basicconcepts/arrayspointers.tex @@ -108,9 +108,9 @@ free(ai); // release memory \end{cppcode} - \begin{goodpracticeWithShortcut}{Don't use C's memory management}{C's memory management} + \begin{goodpractice}[C's memory management]{Don't use C's memory management} Use \cppinline{std::vector} and friends or smart pointers - \end{goodpracticeWithShortcut} + \end{goodpractice} \end{frame} \begin{frame}[fragile] @@ -130,7 +130,7 @@ int* pi = new int{}; delete pi; // release scalar memory \end{cppcode} - \begin{goodpracticeWithShortcut}{Don't use manual memory management}{Manual memory management} + \begin{goodpractice}[Manual memory management]{Don't use manual memory management} Use \cppinline{std::vector} and friends or smart pointers - \end{goodpracticeWithShortcut} + \end{goodpractice} \end{frame} diff --git a/talk/basicconcepts/control.tex b/talk/basicconcepts/control.tex index 42e7e43a..b0e79db9 100644 --- a/talk/basicconcepts/control.tex +++ b/talk/basicconcepts/control.tex @@ -193,11 +193,11 @@ \end{cppcode*} \end{exampleblock} \pause - \begin{goodpracticeWithShortcut}{Don't abuse the \texttt{for} syntax}{\texttt{for} syntax} + \begin{goodpractice}[\texttt{for} syntax]{Don't abuse the \texttt{for} syntax} \begin{itemize} \item The \cppinline{for} loop head should fit in 1-3 lines \end{itemize} - \end{goodpracticeWithShortcut} + \end{goodpractice} \end{frame} \begin{frame}[fragile] diff --git a/talk/basicconcepts/headersinterfaces.tex b/talk/basicconcepts/headersinterfaces.tex index e4d120d4..b46a651e 100644 --- a/talk/basicconcepts/headersinterfaces.tex +++ b/talk/basicconcepts/headersinterfaces.tex @@ -41,12 +41,12 @@ #endif \end{cppcode} \pause - \begin{goodpracticeWithShortcut}{Use preprocessor only in very restricted cases}{preprocessor} + \begin{goodpractice}[preprocessor]{Use preprocessor only in very restricted cases} \begin{itemize} \item Conditional inclusion of headers \item Customization for specific compilers/platforms \end{itemize} - \end{goodpracticeWithShortcut} + \end{goodpractice} \end{frame} \begin{frame}[fragile] diff --git a/talk/morelanguage/raii.tex b/talk/morelanguage/raii.tex index 55d7654d..b3cebfca 100644 --- a/talk/morelanguage/raii.tex +++ b/talk/morelanguage/raii.tex @@ -121,9 +121,9 @@ } \end{cppcode*} \end{exampleblock} - \begin{goodpracticeWithShortcut}{Use \texttt{std::fstream} for file handling}{Use \texttt{std::fstream}} + \begin{goodpractice}[Use \texttt{std::fstream}]{Use \texttt{std::fstream} for file handling} The standard library provides \cppinline{std::fstream} to handle files, use it! - \end{goodpracticeWithShortcut} + \end{goodpractice} \end{frame} \begin{frame}[fragile] @@ -428,9 +428,9 @@ \begin{frame}[fragile] \frametitlecpp[11]{Rule of zero} - \begin{goodpracticeWithShortcut}{Single responsibility principle (SRP)}{Single responsibility principle} + \begin{goodpractice}[Single responsibility principle]{Single responsibility principle (SRP)} Every class should have only one responsibility. - \end{goodpracticeWithShortcut} + \end{goodpractice} \begin{goodpractice}{Rule of zero} \begin{itemize} \item If your class has any special member functions (except ctor.) diff --git a/talk/morelanguage/random.tex b/talk/morelanguage/random.tex index a97dd669..64475f43 100644 --- a/talk/morelanguage/random.tex +++ b/talk/morelanguage/random.tex @@ -116,7 +116,7 @@ \item E.g.: \cppinline{rand() % 10} yields biased numbers and is wrong! \end{itemize} \end{alertblock} - \begin{goodpracticeWithShortcut}{Strongly avoid the C random library}{C random library} + \begin{goodpractice}[C random library]{Strongly avoid the C random library} Use the \cpp11 facilities from the \cppinline{} header - \end{goodpracticeWithShortcut} + \end{goodpractice} \end{frame} diff --git a/talk/morelanguage/stl.tex b/talk/morelanguage/stl.tex index f4555c53..145ce0c7 100644 --- a/talk/morelanguage/stl.tex +++ b/talk/morelanguage/stl.tex @@ -284,12 +284,12 @@ \end{cppcode*} \end{exampleblock} \pause - \begin{goodpracticeWithShortcut}{Use STL algorithms with lambdas}{STL and lambdas} + \begin{goodpractice}[STL and lambdas]{Use STL algorithms with lambdas} \begin{itemize} \item Prefer lambdas over functors when using the STL \item Avoid binders like \cppinline{std::bind2nd}, \cppinline{std::ptr_fun}, etc. \end{itemize} - \end{goodpracticeWithShortcut} + \end{goodpractice} \end{frame} \begin{frame}[fragile] diff --git a/talk/objectorientation/advancedoo.tex b/talk/objectorientation/advancedoo.tex index 621d455b..b56af8eb 100644 --- a/talk/objectorientation/advancedoo.tex +++ b/talk/objectorientation/advancedoo.tex @@ -536,12 +536,12 @@ \item And for rare special cases \end{itemize} \end{goodpractice} - \begin{goodpracticeWithShortcut}{Absolutely avoid diamond-shaped inheritance}{NO diamond inheritance} + \begin{goodpractice}[NO diamond inheritance]{Absolutely avoid diamond-shaped inheritance} \begin{itemize} \item This is a sign that your architecture is not correct \item In case you are tempted, think twice and change your mind \end{itemize} - \end{goodpracticeWithShortcut} + \end{goodpractice} \end{frame} \begin{frame}[fragile] diff --git a/talk/objectorientation/allocations.tex b/talk/objectorientation/allocations.tex index d76ae1f3..8b16db6d 100644 --- a/talk/objectorientation/allocations.tex +++ b/talk/objectorientation/allocations.tex @@ -102,9 +102,9 @@ MyFirstClass *a = new MyFirstClass{3}; } // memory leak !!! \end{cppcode} - \begin{goodpracticeWithShortcut}{Prefer smart pointers over new/delete}{Prefer smart pointer} + \begin{goodpractice}[Prefer smart pointer]{Prefer smart pointers over new/delete} Prefer smart pointers to manage objects (discussed later) - \end{goodpracticeWithShortcut} + \end{goodpractice} \end{frame} \begin{frame}[fragile] @@ -125,7 +125,7 @@ delete[] a; // destructor called 10 times } \end{cppcode} - \begin{goodpracticeWithShortcut}{Prefer containers over new-ed arrays}{Prefer containers} + \begin{goodpractice}[Prefer containers]{Prefer containers over new-ed arrays} Prefer containers to manage collections of objects (discussed later) - \end{goodpracticeWithShortcut} + \end{goodpractice} \end{frame} diff --git a/talk/objectorientation/constructors.tex b/talk/objectorientation/constructors.tex index fb2fbf6e..b719732a 100644 --- a/talk/objectorientation/constructors.tex +++ b/talk/objectorientation/constructors.tex @@ -99,9 +99,9 @@ }; \end{cppcode} \pause - \begin{goodpracticeWithShortcut}{The rule of 3/5 (\cpp98/11) - \href{https://en.cppreference.com/w/cpp/language/rule_of_three}{cppreference}}{Rule of 3/5} + \begin{goodpractice}[Rule of 3/5]{The rule of 3/5 (\cpp98/11) - \href{https://en.cppreference.com/w/cpp/language/rule_of_three}{cppreference}} if a class needs a custom destructor, a copy/move constructor or a copy/move assignment operator, it should have all three/five. - \end{goodpracticeWithShortcut} + \end{goodpractice} \end{frame} \begin{frame}[fragile] From 8ecc52314d0460acab7ddd49b49e6be03a105e87 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Wed, 17 Jan 2024 16:37:12 +0100 Subject: [PATCH 064/156] Add slide on jthread and discuss stop_token. Fix #272 --- talk/concurrency/threadsasync.tex | 97 +++++++++++++++++++++---------- 1 file changed, 66 insertions(+), 31 deletions(-) diff --git a/talk/concurrency/threadsasync.tex b/talk/concurrency/threadsasync.tex index dabaf4ee..8b0a3990 100644 --- a/talk/concurrency/threadsasync.tex +++ b/talk/concurrency/threadsasync.tex @@ -1,50 +1,34 @@ \subsection[thr]{Threads and async} \begin{frame}[fragile] - \frametitle{Basic concurrency \hfill \cpp11/\cpp20} + \frametitlecpp[11]{Basic concurrency} \begin{block}{Threading} \begin{itemize} \item \cpp11 added \cppinline{std::thread} in \cppinline{} header \item takes a function as argument of its constructor \item must be detached or joined before the main thread terminates - \item \cpp20: \cppinline{std::jthread} automatically joins at destruction \end{itemize} \end{block} - \vspace{-1\baselineskip} - \begin{overprint} - \onslide<1> - \begin{exampleblock}{Example code} - \begin{cppcode*}{gobble=2} - void foo() {...} - void bar() {...} - int main() { - std::thread t1{foo}; - std::thread t2{bar}; - for (auto t: {&t1,&t2}) t->join(); - return 0; - } - \end{cppcode*} - \end{exampleblock} - \onslide<2> - \begin{exampleblock}{Example with jthread (\cpp20)} - \begin{cppcode*}{gobble=2} - void foo() {...} - void bar() {...} - int main() { - std::jthread t1{foo}; - std::jthread t2{bar}; - return 0; - } - \end{cppcode*} - \end{exampleblock} - \end{overprint} + + \begin{exampleblock}{Example code} + \begin{cppcode*}{gobble=2} + void foo() {...} + void bar() {...} + int main() { + std::thread t1{foo}; + std::thread t2{bar}; + for (auto t: {&t1,&t2}) t->join(); + return 0; + } + \end{cppcode*} + \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitlecpp[11]{The thread constructor} \begin{exampleblock}{Can take a function and its arguments} \begin{cppcode*}{} - void function(int j, double j) {...}; + void function(int j, double j) {...} std::thread t1{function, 1, 2.0}; \end{cppcode*} \end{exampleblock} @@ -64,6 +48,57 @@ \end{exampleblock} \end{frame} +\begin{frame}[fragile] + \frametitlecpp[20]{\texttt{std::jthread}} + \begin{goodpractice}[jthread vs.\ thread]{Prefer \cppinline{std::jthread} if \cpp20 is available} + \begin{itemize} + \item In \cppinline{} header since \cpp20 + \item Automatically joins on destruction + \item Can be stopped from outside + \end{itemize} + \end{goodpractice} + + \begin{exampleblock}{Example with jthread} + \begin{cppcode*}{gobble=2} + void foo() {...} + void bar() {...} + int main() { + std::jthread t1{foo}; + std::jthread t2{bar}; t2.request_stop(); + // No join required + return 0; + } + \end{cppcode*} + \end{exampleblock} +\end{frame} + +\begin{frame}[fragile] + \frametitlecpp[20]{Using jthread's stop\_token} + \begin{block}{} + \begin{itemize} + \item Like \cppinline{std::thread}, \cppinline{jthread} can take a function or functors/lambdas and their arguments + \item New: Can take functions that handle \cppinline{stop_token}s + \end{itemize} + \end{block} + \begin{exampleblock}{stop\_token in a function} + \begin{cppcode*}{} + void function(std::stop_token st, int j) { + while (!st.stop_requested()) { + // ... + }} + std::jthread t1{function, 1}; + t1.request_stop(); + \end{cppcode*} + \end{exampleblock} + \begin{exampleblock}{A lambda with a stop\_token} + \begin{cppcode*}{} + std::jthread t1{ + [](std::stop_token st, int i){ ... }, 1}; + \end{cppcode*} + \end{exampleblock} +\end{frame} + + \begin{frame}[fragile] \frametitlecpp[11]{Basic asynchronicity} \begin{block}{Concept} From 81a93fd22c94525936ad2353610bf1429f655adf Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Thu, 18 Jan 2024 10:22:10 +0100 Subject: [PATCH 065/156] Fix publication of essentials slides Due to a change in how to switch between basic and full course, the publish-slides workflow would always build the full course. --- .github/workflows/publish-slides.yml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/publish-slides.yml b/.github/workflows/publish-slides.yml index 62483d46..63d2f45c 100644 --- a/.github/workflows/publish-slides.yml +++ b/.github/workflows/publish-slides.yml @@ -14,10 +14,17 @@ jobs: version: [ essentials, full ] steps: - uses: actions/checkout@v4 - - name: Setup essentials course + - name: Compile Essentials document if: matrix.version == 'essentials' - run: echo '\basictrue' > talk/onlybasics.tex - - name: Compile LaTeX document + uses: xu-cheng/latex-action@v3 + with: + root_file: C++Course.tex + latexmk_use_xelatex: true + args: -f -pdf -interaction=nonstopmode -shell-escape -usepretex=\def\makebasic{} + working_directory: talk + extra_system_packages: "py-pygments" + - name: Compile Full document + if: matrix.version == 'full' uses: xu-cheng/latex-action@v3 with: root_file: C++Course.tex From c047ae2621e1455a3605ccd99359b34c9593cd15 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 19 Jan 2024 15:07:29 +0100 Subject: [PATCH 066/156] Refine constplay exercise. Fix #452. --- exercises/constness/Makefile | 2 +- exercises/constness/constplay.cpp | 42 +++++++++++++++++++++++-------- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/exercises/constness/Makefile b/exercises/constness/Makefile index a4e309c2..2e3eb578 100644 --- a/exercises/constness/Makefile +++ b/exercises/constness/Makefile @@ -4,4 +4,4 @@ clean: rm -f *o constplay *~ constplay.sol constplay : constplay.cpp - ${CXX} -Wall -Wextra -L. -o $@ $< + ${CXX} -std=c++17 -Wall -Wextra -L. -o $@ $< diff --git a/exercises/constness/constplay.cpp b/exercises/constness/constplay.cpp index ab3b9a04..31327001 100644 --- a/exercises/constness/constplay.cpp +++ b/exercises/constness/constplay.cpp @@ -7,19 +7,25 @@ */ void copy(int a) { [[maybe_unused]] int val = a; -}; +} void copyConst(const int a) { [[maybe_unused]] int val = a; -}; +} void write(int* a) { *a = 42; -}; +} +void write(int& a) { + a = 42; +} -void read(const int *a) { +void read(const int* a) { [[maybe_unused]] int val = *a; -}; +} +void read(int const & a) { + [[maybe_unused]] int val = a = 2; +} struct Test { void hello(std::string &s) { @@ -56,12 +62,24 @@ int main() { copyConst(m); // try constant arguments of functions with pointers - int *p = 0; - const int *r = 0; - write(p); - write(r); - read(p); - read(r); + { + int *p = 0; + const int *r = 0; + write(p); + write(r); + read(p); + read(r); + } + + // try constant arguments of functions with references + { + int p = 0; + const int r = 0; + write(2); + write(r); + read(2); + read(r); + } // try constant method in a class Test t; @@ -71,4 +89,6 @@ int main() { tc.hello(s); t.helloConst(s); tc.helloConst(s); + + return 0; } From a4ec470c26985b1c96bed84c7aa7e47a5377a4ca Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 19 Jan 2024 14:35:02 +0100 Subject: [PATCH 067/156] Add an exercise on UBSan. --- exercises/ubsan/README.md | 23 +++++++ .../ubsan/solution/undefinedBehaviour.cpp | 60 +++++++++++++++++++ exercises/ubsan/undefinedBehaviour.cpp | 60 +++++++++++++++++++ 3 files changed, 143 insertions(+) create mode 100644 exercises/ubsan/README.md create mode 100644 exercises/ubsan/solution/undefinedBehaviour.cpp create mode 100644 exercises/ubsan/undefinedBehaviour.cpp diff --git a/exercises/ubsan/README.md b/exercises/ubsan/README.md new file mode 100644 index 00000000..8569f39f --- /dev/null +++ b/exercises/ubsan/README.md @@ -0,0 +1,23 @@ +# Undefined Behaviour Sanitizer + +This directory contains a program that's full of evil bugs. Many of those would cause compiler warnings, +but the problems can easily be obscured by making the code slightly more complicated, e.g. by passing +pointers or indices through functions or similar. + +UBSan is a run-time tool, so it can catch these bugs even if the compilers don't emit warnings. +This should illustrate why every larger project should have a UBSan and a ASan build as part of +it Continuous Integration. + +## Instructions + +- Compile and run this program using a compiler invocation like + ` -g -std=c++17 -o undefinedBehaviour undefinedBehaviour.cpp` + +- You might see warnings depending on the compiler, but on most platforms the program runs without observable issues. + +- Recompile with "-fsanitize=undefined", and observe that almost every second line contains a serious bug. + NOTE: If this fails, your compiler does not support UBSan (yet). In this case, you can try to read the + program and catch the bugs, or continue with the next exercise. + +- Try to understand what's wrong. The solution contains a few comments what kind of bugs are hidden in the program. + diff --git a/exercises/ubsan/solution/undefinedBehaviour.cpp b/exercises/ubsan/solution/undefinedBehaviour.cpp new file mode 100644 index 00000000..46403c75 --- /dev/null +++ b/exercises/ubsan/solution/undefinedBehaviour.cpp @@ -0,0 +1,60 @@ +#include +#include + +// You don't need to change any code in these structs: +struct Base { + virtual void print() = 0; + virtual ~Base() {} +}; +struct Derived1 : public Base { + void print() override { + std::cout << "Derived1::print()\n"; + } +}; +struct Derived2 : public Base { + void print() override { + std::cout << "Derived2::print()\n"; + } +}; + + +/** + * *************** + * Instructions: + * *************** + * + * Compile and run this program using a compiler invocation like + * -g -std=c++17 -o undefinedBehaviour undefinedBehaviour.cpp + * + * You might see warnings depending on the compiler, but on most platforms the program runs without observable issues. + * Smart compilers will warn with most of these bugs, but the compilers can easily be deceived by hiding a nullptr in + * a variable, or passing it as a function argument or similar. + * + * Since UBSan does runtime checks, it will catch these errors even if they are obscured. + * Recompile with "-fsanitize=undefined", and observe that almost every second line contains a serious bug. + * Try to understand what's wrong. + */ + +int runTests() { + int arr[] = {1, 2, 3, 4}; + std::cout << "arr[4]=" << arr[4] << "\n"; // Array overrun + + unsigned short s = 1; + std::cout << "s << 33=" << (s << 33) << "\n"; // We cannot shift a type with 32 bits by 33 bits. + + int i = std::numeric_limits::max(); + std::cout << "i + 1 =" << i + 1 << "\n"; // Adding 1 to max int overflows to min int + + Derived1 d1; + Base & base = d1; + auto & d2 = static_cast(base); // Casting an original d1 to d2 is wrong + d2.print(); // Calling a function on a wrongly-cast object is wrong + + Derived2 * d2ptr = nullptr; + Derived2 & nullref = static_cast(*d2ptr); // Cannot bind references to a wrong address +} // Forgot to return a value + +int main() { + const auto result = runTests(); + return result; +} diff --git a/exercises/ubsan/undefinedBehaviour.cpp b/exercises/ubsan/undefinedBehaviour.cpp new file mode 100644 index 00000000..037b2139 --- /dev/null +++ b/exercises/ubsan/undefinedBehaviour.cpp @@ -0,0 +1,60 @@ +#include +#include + +// You don't need to change any code in these structs: +struct Base { + virtual void print() = 0; + virtual ~Base() {} +}; +struct Derived1 : public Base { + void print() override { + std::cout << "Derived1::print()\n"; + } +}; +struct Derived2 : public Base { + void print() override { + std::cout << "Derived2::print()\n"; + } +}; + + +/** + * *************** + * Instructions: + * *************** + * + * Compile and run this program using a compiler invocation like + * -g -std=c++17 -o undefinedBehaviour undefinedBehaviour.cpp + * + * You might see warnings depending on the compiler, but on most platforms the program runs without observable issues. + * Smart compilers will warn with most of these bugs, but the compilers can easily be deceived by hiding a nullptr in + * a variable, or passing it as a function argument or similar. + * + * Since UBSan does runtime checks, it will catch these errors even if they are obscured. + * Recompile with "-fsanitize=undefined", and observe that almost every second line contains a serious bug. + * Try to understand what's wrong. + */ + +int runTests() { + int arr[] = {1, 2, 3, 4}; + std::cout << "arr[4]=" << arr[4] << "\n"; + + unsigned short s = 1; + std::cout << "s << 33=" << (s << 33) << "\n"; + + int i = std::numeric_limits::max(); + std::cout << "i + 1 =" << i + 1 << "\n"; + + Derived1 d1; + Base & base = d1; + auto & d2 = static_cast(base); + d2.print(); + + Derived2 * d2ptr = nullptr; + Derived2 & nullref = static_cast(*d2ptr); +} + +int main() { + const auto result = runTests(); + return result; +} From 0f1803995e850773ae509e1759eb9a1af16d77bd Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 19 Jan 2024 14:37:51 +0100 Subject: [PATCH 068/156] Add UBSan exercise to Advanced Course schedule. --- exercises/ExerciseSchedule_AdvancedCourse.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/exercises/ExerciseSchedule_AdvancedCourse.md b/exercises/ExerciseSchedule_AdvancedCourse.md index bd0c98cd..071685da 100644 --- a/exercises/ExerciseSchedule_AdvancedCourse.md +++ b/exercises/ExerciseSchedule_AdvancedCourse.md @@ -36,6 +36,8 @@ People should replay them and discover the tools by themselves. ### (optional) Address sanitizer (directory: [`asan`](asan), [cheatSheet](ExercisesCheatSheet.md#address-sanitizer-directory-asan)) +### (optional) Undefined behaviour sanitizer (directory: [`ubsan`](ubsan) + Day 3 ----- From 68a2f491d5e6f8560667a76c99a152bde5aaa0e5 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 19 Jan 2024 14:46:49 +0100 Subject: [PATCH 069/156] Add slide on UBSan exercise. --- talk/tools/sanitizers.tex | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/talk/tools/sanitizers.tex b/talk/tools/sanitizers.tex index ef2f86f3..3948b081 100644 --- a/talk/tools/sanitizers.tex +++ b/talk/tools/sanitizers.tex @@ -260,3 +260,16 @@ \url{https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html} \end{block} \end{frame} + +\begin{frame}[fragile] + \frametitle{Undefined Behaviour Sanitizer (UBSan)} + \begin{exercise}{Finding evil run-time bugs} + \begin{itemize} + \item Go to \texttt{exercises/ubsan} + \item Compile and run the program following the instructions in README or in the program + \item The program should run without observable issues + \item Recompile with UBSan and see that almost every second line contains evil bugs + \end{itemize} + \end{exercise} + +\end{frame} From dd0a658cee24e3c7b0c372b0eabd2d9d00a9ff87 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 19 Jan 2024 13:47:17 +0000 Subject: [PATCH 070/156] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- exercises/ubsan/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/exercises/ubsan/README.md b/exercises/ubsan/README.md index 8569f39f..b901ef7a 100644 --- a/exercises/ubsan/README.md +++ b/exercises/ubsan/README.md @@ -20,4 +20,3 @@ it Continuous Integration. program and catch the bugs, or continue with the next exercise. - Try to understand what's wrong. The solution contains a few comments what kind of bugs are hidden in the program. - From 07f646f74fbf50d28f7e1a4db9d12c424cc6d9fe Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Mon, 22 Jan 2024 09:55:19 +0100 Subject: [PATCH 071/156] Change a type in UBSan exercise --- exercises/ubsan/undefinedBehaviour.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/ubsan/undefinedBehaviour.cpp b/exercises/ubsan/undefinedBehaviour.cpp index 037b2139..d5926385 100644 --- a/exercises/ubsan/undefinedBehaviour.cpp +++ b/exercises/ubsan/undefinedBehaviour.cpp @@ -39,7 +39,7 @@ int runTests() { int arr[] = {1, 2, 3, 4}; std::cout << "arr[4]=" << arr[4] << "\n"; - unsigned short s = 1; + unsigned int s = 1; std::cout << "s << 33=" << (s << 33) << "\n"; int i = std::numeric_limits::max(); From 4853595d79327e158f34a18728ebff418234c66c Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Mon, 22 Jan 2024 09:55:51 +0100 Subject: [PATCH 072/156] Update solution of UBSan exercise --- exercises/ubsan/solution/undefinedBehaviour.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/ubsan/solution/undefinedBehaviour.cpp b/exercises/ubsan/solution/undefinedBehaviour.cpp index 46403c75..1101161d 100644 --- a/exercises/ubsan/solution/undefinedBehaviour.cpp +++ b/exercises/ubsan/solution/undefinedBehaviour.cpp @@ -39,7 +39,7 @@ int runTests() { int arr[] = {1, 2, 3, 4}; std::cout << "arr[4]=" << arr[4] << "\n"; // Array overrun - unsigned short s = 1; + unsigned int s = 1; std::cout << "s << 33=" << (s << 33) << "\n"; // We cannot shift a type with 32 bits by 33 bits. int i = std::numeric_limits::max(); From 83a7bdb6d2555cd9f4463cd5f9cae09ccb4d90bc Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Wed, 28 Feb 2024 14:44:39 +0100 Subject: [PATCH 073/156] Make functions exercise less confusing. After the functions exercise has been modernised (no arrays, std::string instead), there is no need to print "fiveCharacters". The exercise is about pass by copy vs pass by reference and overloading, so the confusing instructions have been removed. Fix #426 --- exercises/functions/README.md | 6 +-- exercises/functions/Structs.cpp | 2 +- exercises/functions/functions.cpp | 15 ++++--- .../functions/solution/functions.sol.cpp | 40 +++++++++---------- 4 files changed, 29 insertions(+), 34 deletions(-) diff --git a/exercises/functions/README.md b/exercises/functions/README.md index 8bdaba52..17fd9784 100644 --- a/exercises/functions/README.md +++ b/exercises/functions/README.md @@ -14,7 +14,7 @@ They are exactly what their name says, so let's try to avoid copying the latter. ## Step 2 -Using `printFiveCharacters()` as an example, write a function that prints the first five characters of `SlowToCopy`. Call it in `main()`. +Using `printName()` as an example, write a function that prints the name of `SlowToCopy`. Call it in `main()`. ## Step 3 @@ -22,6 +22,6 @@ Try passing by copy and passing by reference, see the difference. ## Step 4 -When passing by reference, ensure that your `printFiveCharacters` cannot inadvertently modify the original object. -To test its const correctness, try adding something like `argument.name[0] = 'a';` to your print function. +When passing by reference, ensure that your `printName` cannot inadvertently modify the original object. +To test its const correctness, try adding something like `argument.name = "a";` to your print function. Try both with and without const attributes in your print function's signature. diff --git a/exercises/functions/Structs.cpp b/exercises/functions/Structs.cpp index bf312925..4f24a9d3 100644 --- a/exercises/functions/Structs.cpp +++ b/exercises/functions/Structs.cpp @@ -6,7 +6,7 @@ #include /// Construct a new instance of SlowToCopy. -SlowToCopy::SlowToCopy() : name("Large type") {} +SlowToCopy::SlowToCopy() : name("SlowToCopy") {} /// Construct a new instance of SlowToCopy. SlowToCopy::SlowToCopy(const std::string& name) : name(name) {} diff --git a/exercises/functions/functions.cpp b/exercises/functions/functions.cpp index c2089bef..c532bcb6 100644 --- a/exercises/functions/functions.cpp +++ b/exercises/functions/functions.cpp @@ -4,30 +4,29 @@ * FastToCopy * SlowToCopy * They are exactly what their name says, so let's try to avoid copying the latter. - * 2. Using "printFiveCharacters()" as an example, write a function that prints the first five characters of "SlowToCopy". + * 2. Using "printName()" as an example, write a function that prints the name of "SlowToCopy". * Call it in main(). * 3. Try passing by copy and passing by reference, see the difference. - * 4. When passing by reference, ensure that your "printFiveCharacters" cannot inadvertently modify the original object. + * 4. When passing by reference, ensure that your "printName" cannot inadvertently modify the original object. * To test its const correctness, try adding something like - * argument.name[0] = 'a'; + * argument.name = "other name"; * to your print function. * Try both with and without const attributes in your print function's signature. - * 5. Bonus: Can you fix "printFiveCharacters" to actually only print the first five characters and not the entire string? */ #include "Structs.h" // The data structs we will work with #include // For printing -void printFiveCharacters(FastToCopy argument) { +void printName(FastToCopy argument) { std::cout << argument.name << '\n'; } int main() { - FastToCopy fast = {"abcdefghijkl"}; - printFiveCharacters(fast); + FastToCopy fast = {"Fast"}; + printName(fast); - SlowToCopy slow = {"ABCDEFGHIJKL"}; + SlowToCopy slow = {"Slow"}; // print it here return 0; diff --git a/exercises/functions/solution/functions.sol.cpp b/exercises/functions/solution/functions.sol.cpp index 50c39f66..543e8c0c 100644 --- a/exercises/functions/solution/functions.sol.cpp +++ b/exercises/functions/solution/functions.sol.cpp @@ -4,12 +4,12 @@ * FastToCopy * SlowToCopy * They are exactly what their name says, so let's try to avoid copying the latter. - * 2. Using "printFiveCharacters()" as an example, write a function that prints the first five characters of "SlowToCopy". + * 2. Using "printName()" as an example, write a function that prints the name of "SlowToCopy". * Call it in main(). * 3. Try passing by copy and passing by reference, see the difference. - * 4. When passing by reference, ensure that your "printFiveCharacters" cannot inadvertently modify the original object. + * 4. When passing by reference, ensure that your "printName" cannot inadvertently modify the original object. * To test its const correctness, try adding something like - * argument.name[0] = 'a'; + * argument.name = "other name"; * to your print function. * Try both with and without const attributes in your print function's signature. */ @@ -18,37 +18,33 @@ #include // For printing -void printFiveCharacters(FastToCopy argument) { - for (int i = 0; i < 5; i++) - std::cout << argument.name[i]; - std::cout << '\n'; - - // alternative 1: std::cout << argument.name.substr(0, 5) << '\n'; - // alternative 2: std::cout << std::string_view{argument.name.data(), 5} << '\n'; - // alternative C: std::printf("%.5s\n", argument.name.c_str()); - // alternative C++23: std::print("{:.5}\n", argument); +void printName(FastToCopy argument) { + std::cout << argument.name << '\n'; } -void printFiveCharacters(const SlowToCopy & argument) { - //argument.data[0] = '\n' ; // EXPECTED COMPILATION ERROR +void inefficientPrintName(SlowToCopy argument) { std::cout << argument.name << '\n'; + + // We can change the argument's name because it's a copy: + argument.name = "New name"; } -void printFiveCharactersWithCopy(SlowToCopy argument) { +void printName(const SlowToCopy & argument) { std::cout << argument.name << '\n'; - // We can actually modify the argument if we want, since it's a copy: - argument.name[0] = 'a'; + + // We are unable to change name, as we should: + //argument.name = '\n'; } int main() { - FastToCopy fast = {"abcdefghijkl"}; - printFiveCharacters(fast); + FastToCopy fast = {"Fast"}; + printName(fast); - SlowToCopy slow = {"ABCDEFGHIJKL"}; - printFiveCharacters(slow); + SlowToCopy slow = {"Slow"}; + printName(slow); std::cout << "Now printing with copy:\n"; - printFiveCharactersWithCopy(slow); + inefficientPrintName(slow); return 0; } From d4645c95e2093b5893a77cef71bf5ccfca0c6de2 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 19 Jan 2024 11:08:04 +0100 Subject: [PATCH 074/156] Elaborate on header/source separation and move "this" slide to advanced OO. Fix #428 Co-authored by BMG. --- talk/basicconcepts/headersinterfaces.tex | 20 ++++++++++++ talk/objectorientation/advancedoo.tex | 39 +++++++++++++++++++++++ talk/objectorientation/inheritance.tex | 1 - talk/objectorientation/objectsclasses.tex | 32 +++---------------- 4 files changed, 64 insertions(+), 28 deletions(-) diff --git a/talk/basicconcepts/headersinterfaces.tex b/talk/basicconcepts/headersinterfaces.tex index b46a651e..84e8ba57 100644 --- a/talk/basicconcepts/headersinterfaces.tex +++ b/talk/basicconcepts/headersinterfaces.tex @@ -73,3 +73,23 @@ \end{cppcode*} \end{block} \end{frame} + +\begin{frame}[fragile] + \frametitlecpp[98]{Header / source separation} + \begin{goodpractice}[Header / source]{Headers and source files} + \begin{itemize} + \item Headers should contain declarations of functions / classes + \begin{itemize} + \item Only create them if interface is used somewhere else + \end{itemize} + \item Might be included/compiled many times + \item Good to keep them short + \item Minimise \cppinline{#include} statements + \item Put long code in implementation files. Exceptions: + \begin{itemize} + \item Short functions + \item Templates and constexpr functions + \end{itemize} + \end{itemize} + \end{goodpractice} +\end{frame} diff --git a/talk/objectorientation/advancedoo.tex b/talk/objectorientation/advancedoo.tex index b56af8eb..8e936bfc 100644 --- a/talk/objectorientation/advancedoo.tex +++ b/talk/objectorientation/advancedoo.tex @@ -1,5 +1,44 @@ \subsection[advOO]{Advanced OO} +\begin{frame}[fragile] + \frametitlecpp[98]{\texttt{this} keyword} + \begin{block}{How to know an object's address?} + \begin{itemize} + \item Sometimes we need the address of the current object + \item Or we need to pass our address / a reference to a different entity + (for example to implement operators, see later) + \item All class methods can use the keyword \cppinline{this} + \begin{itemize} + \item It returns the address of the current object + \item Its type is \cppinline{T*} in the methods of a class {\ttfamily T} + \end{itemize} + \end{itemize} + \end{block} + \begin{minipage}{0.7\textwidth} + \begin{cppcode} + struct S { + int a,b; + // these two are the same: + int getB() { return b; } // 5 + int getB() { return this->b; } // 5 + void testAddress() { + S* addr = this; // 0x3000 + } + } s{2,5}; + \end{cppcode} + \end{minipage}% + \hfil% + \begin{minipage}{0.3\textwidth} + \begin{tikzpicture} + \memorystack[size x=2cm,word size=1,block size=4,nb blocks=4] + \memorypush{a = 2} + \memorypush{b = 5} + \memorystruct{1}{2}{\tiny s} + \draw[-Triangle,thick] (\stacksizex-1*\stacksizey,-1*\stacksizey) node[left] {\footnotesize \cppinline{this} pointer} -- (\stacksizex,-0.1*\stacksizey); + \end{tikzpicture} + \end{minipage} +\end{frame} + \begin{frame}[fragile] \frametitlecpp[98]{Polymorphism} \begin{block}{the concept} diff --git a/talk/objectorientation/inheritance.tex b/talk/objectorientation/inheritance.tex index 6645ca39..9b5d76ec 100644 --- a/talk/objectorientation/inheritance.tex +++ b/talk/objectorientation/inheritance.tex @@ -42,7 +42,6 @@ \memorypush{a = 2} \memorypush{b = 5} \memorystruct{1}{2}{\tiny myobj2} - \draw[-Triangle,thick] (\stacksizex-1*\stacksizey,-1*\stacksizey) node[left] {\footnotesize \cppinline{this} pointer} -- (\stacksizex,-0.1*\stacksizey); \end{tikzpicture} \end{overprint} \vfill \null diff --git a/talk/objectorientation/objectsclasses.tex b/talk/objectorientation/objectsclasses.tex index 814b50a2..dd9dd1df 100644 --- a/talk/objectorientation/objectsclasses.tex +++ b/talk/objectorientation/objectsclasses.tex @@ -117,40 +117,18 @@ \item some functions (templates, \cppinline{constexpr}) must be in the header \end{itemize} \end{goodpractice} - \begin{cppcode} + \begin{block}{} + \begin{cppcode} + #include "MyFirstClass.hpp" + void MyFirstClass::squareA() { a *= a; } - int MyFirstClass::sum(int b) { return a + b; } - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{\texttt{this} keyword} - \begin{block}{How to know an object's address?} - \begin{itemize} - \item Sometimes we need to pass a reference to ourself to a different entity - \item For example to implement operators, see later - \item All class methods can use the keyword \cppinline{this} - \begin{itemize} - \item It returns the address of the current object - \item Its type is \cppinline{T*} in the methods of a class {\ttfamily T} - \end{itemize} - \end{itemize} + \end{cppcode} \end{block} - \begin{cppcode} - void freeFunc(S & s); - struct S { - void memberFunc() { // Implicit S* parameter - freeFunc(*this); // Pass a reference to ourself - } - }; - S s; - s.memberFunc(); // Passes &s implicitly - \end{cppcode} \end{frame} \begin{frame}[fragile] From d42770b9e3156df4affedeff0617c7cc039f7153 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 19 Jan 2024 11:14:43 +0100 Subject: [PATCH 075/156] Implement comments from 6th and JLab lectures #428. Co-authored-by: Bernhard Manfred Gruber --- talk/objectorientation/advancedoo.tex | 19 +++++++++++-------- talk/objectorientation/inheritance.tex | 7 +++---- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/talk/objectorientation/advancedoo.tex b/talk/objectorientation/advancedoo.tex index 8e936bfc..b74d3a1d 100644 --- a/talk/objectorientation/advancedoo.tex +++ b/talk/objectorientation/advancedoo.tex @@ -571,15 +571,18 @@ \frametitlecpp[98]{Multiple inheritance advice} \begin{goodpractice}{Avoid multiple inheritance} \begin{itemize} - \item Except for inheriting from interfaces - \item And for rare special cases - \end{itemize} - \end{goodpractice} - \begin{goodpractice}[NO diamond inheritance]{Absolutely avoid diamond-shaped inheritance} - \begin{itemize} - \item This is a sign that your architecture is not correct - \item In case you are tempted, think twice and change your mind + \item Except for inheriting from interfaces (=no data members) + \item And for rare special cases \end{itemize} + + \hspace*{0.05\textwidth}\begin{minipage}{0.9\textwidth} + \begin{alertblock}{Absolutely avoid diamond-shape inheritance} + \begin{itemize} + \item This is a sign that your architecture is not correct + \item In case you are tempted, think twice and change your mind + \end{itemize} + \end{alertblock} + \end{minipage} \end{goodpractice} \end{frame} diff --git a/talk/objectorientation/inheritance.tex b/talk/objectorientation/inheritance.tex index 9b5d76ec..0d0a0f7b 100644 --- a/talk/objectorientation/inheritance.tex +++ b/talk/objectorientation/inheritance.tex @@ -57,10 +57,9 @@ \end{description} \begin{itemize} \item The default for \texttt{class} is \cppinline{private} - \item A \cppinline{struct} is just a class that defaults to \cppinline{public} access + \item The default for \texttt{struct} is \cppinline{public} \end{itemize} \end{block} - \pause \begin{multicols}{2} \begin{cppcode*}{gobble=2} class MyFirstClass { @@ -207,7 +206,7 @@ \draw[very thick,-Triangle] (MyThirdClass)--(MySecondClass) node[midway,right] {public}; \end{tikzpicture} \columnbreak - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{gobble=2,highlightlines=14} void funcSecond() { int a = priv; // Error int b = prot; // OK @@ -249,7 +248,7 @@ \draw[very thick,-Triangle] (MyThirdClass)--(MySecondClass) node[midway,right] {public}; \end{tikzpicture} \columnbreak - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{gobble=2,highlightlines=8-9} void funcSecond() { int a = priv; // Error int b = prot; // OK From 4e9228b0db3e22de6c06996b72d461faef62d5ba Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 19 Jan 2024 11:15:56 +0100 Subject: [PATCH 076/156] Mention possible operator symbols (#428). --- talk/objectorientation/operators.tex | 36 +++++++++++++++++----------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/talk/objectorientation/operators.tex b/talk/objectorientation/operators.tex index fe86d09f..d5d83477 100644 --- a/talk/objectorientation/operators.tex +++ b/talk/objectorientation/operators.tex @@ -17,28 +17,36 @@ \end{cppcode} \end{frame} -\begin{frame} +\begin{frame}[fragile] \frametitlecpp[98]{Operator overloading} \begin{block}{Defining operators for a class} \begin{itemize} \item implemented as a regular method \begin{itemize} - \item either inside the class, as a member function + \item \small either inside the class, as a member function \item or outside the class (not all) \end{itemize} - \item with a special name (replace @ by anything) - \begin{tabular}{llll} - Expression & As member & As non-member \\ - \hline - @a & (a).operator@() & operator@(a) \\ - a@b & (a).operator@(b) & operator@(a,b) \\ - a=b & (a).operator=(b) & cannot be non-member \\ - a(b...) & (a).operator()(b...) & cannot be non-member \\ - a[b] & (a).operator[](b) & cannot be non-member \\ - a-\textgreater & (a).operator-\textgreater() & cannot be non-member \\ - a@ & (a).operator@(0) & operator@(a,0) \\ - \end{tabular} + \item with a special name (replace @ by operators from below)\small \end{itemize} + \begin{tabular}{llll} + Expression & As member & As non-member \\ + \hline + @a & (a).operator@() & operator@(a) \\ + a@b & (a).operator@(b) & operator@(a,b) \\ + a=b & (a).operator=(b) & cannot be non-member \\ + a(b...) & (a).operator()(b...) & cannot be non-member \\ + a[b] & (a).operator[](b) & cannot be non-member \\ + a-\textgreater & (a).operator-\textgreater() & cannot be non-member \\ + a@ & (a).operator@(0) & operator@(a,0) \\ + \hline + \end{tabular} + + \small + \begin{cppcode*}{linenos=false} + possible operators: + - * / % ^ & | ~ ! = < > + += -= *= /= %= ^= &= |= << >> >>= <<= + == != <= >= <=> && || ++ -- , ->* -> () [] + \end{cppcode*} \end{block} \end{frame} From 6e6e13b2342fcd78e818037bd67d463f9be822d5 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 19 Jan 2024 11:16:20 +0100 Subject: [PATCH 077/156] Slightly shorten braces for marking structs in memorystack. When two structs are shown in top of each other in the stacks, the braces touch. By shortening them by 2pt, there is a visual separation now. --- talk/setup.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/talk/setup.tex b/talk/setup.tex index 709dfdda..2b30ee3d 100644 --- a/talk/setup.tex +++ b/talk/setup.tex @@ -401,7 +401,7 @@ \memorystackset{ size y/.get=\stacksizey } - \draw[snake=brace,thick] (-2pt,#1*\stacksizey-\stacksizey) -- (-2pt,#2*\stacksizey) + \draw[snake=brace,thick] (-2pt,#1*\stacksizey-\stacksizey+2pt) -- (-2pt,#2*\stacksizey-2pt) node [midway, above, sloped] {#3}; } From 42772c7929afdfad4df97c40db0f526119ce6687 Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Fri, 22 Mar 2024 20:45:34 +0100 Subject: [PATCH 078/156] updated compiler versions for the latest C++ versions --- talk/introduction/history.tex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/talk/introduction/history.tex b/talk/introduction/history.tex index b0fd56d1..feb2219c 100644 --- a/talk/introduction/history.tex +++ b/talk/introduction/history.tex @@ -113,7 +113,8 @@ 11 & $\geq$4.8 & $\geq$3.3\\ 14 & $\geq$4.9 & $\geq$3.4\\ 17 & $\geq$7.3 & $\geq$5\\ - 20 & $>$11 & $>$12 \\ + 20 & $>$11, 14 & $>$12,18 \\ + 23 & $>$14 & $>$17,18 \\ \end{tabular} \caption{Minimum versions of gcc and clang for a given \cpp version} \end{center} From f0c420740c6b4bdd169cfe1e728d77f76e207956 Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Tue, 26 Mar 2024 10:59:55 +0100 Subject: [PATCH 079/156] tiny fixes from 10th editoin of the course --- talk/basicconcepts/control.tex | 2 +- talk/objectorientation/objectsclasses.tex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/talk/basicconcepts/control.tex b/talk/basicconcepts/control.tex index b0e79db9..3dca64cc 100644 --- a/talk/basicconcepts/control.tex +++ b/talk/basicconcepts/control.tex @@ -179,7 +179,7 @@ \end{cppcode*} \vspace{-0.2cm} \begin{itemize} - \item Initializations and increments are comma separated + \item Multiple initializations / increments are comma separated \item Initializations can contain declarations \item Braces are optional if loop body is a single statement \end{itemize} diff --git a/talk/objectorientation/objectsclasses.tex b/talk/objectorientation/objectsclasses.tex index dd9dd1df..fc5e69c0 100644 --- a/talk/objectorientation/objectsclasses.tex +++ b/talk/objectorientation/objectsclasses.tex @@ -145,7 +145,7 @@ int a; int sum(int b); int sum(int b, int c); - } + }; int MyFirstClass::sum(int b) { return a + b; } From b903cea9e206b76524b6acc860c798ba7535dd86 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Thu, 28 Mar 2024 11:25:45 +0100 Subject: [PATCH 080/156] Add gdb tui to list of debugger interfaces. --- talk/tools/debugging.tex | 1 + 1 file changed, 1 insertion(+) diff --git a/talk/tools/debugging.tex b/talk/tools/debugging.tex index e68f3b15..84644c16 100644 --- a/talk/tools/debugging.tex +++ b/talk/tools/debugging.tex @@ -76,6 +76,7 @@ \item windows for variables, breakpoints, call stack, active threads, watch variables in-code, disassembly, run to cursor ... \end{itemize} \begin{description} + \item[Native gdb] Try ``tui enable'' for a simple built-in UI \item[\href{https://code.visualstudio.com/docs/cpp/cpp-debug}{\beamergotobutton{VSCode}}] Built-in support for gdb \item[\href{https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb}{\beamergotobutton{CodeLLDB}}] From 36caa0554838960b7fd7236c151a21d959a32875 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Thu, 28 Mar 2024 15:25:21 +0100 Subject: [PATCH 081/156] Init two pointers in const exercise. Although the exercise is mostly about battling with the compiler, once people finish this work, they will encounter a crash when running the program. Here, we init the two pointers to &a and &b to create a runnable program. --- exercises/constness/constplay.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/constness/constplay.cpp b/exercises/constness/constplay.cpp index 31327001..d8811d8a 100644 --- a/exercises/constness/constplay.cpp +++ b/exercises/constness/constplay.cpp @@ -63,8 +63,8 @@ int main() { // try constant arguments of functions with pointers { - int *p = 0; - const int *r = 0; + int *p = &a; + const int *r = &b; write(p); write(r); read(p); From 5658dae8aa5fc084ec74b1276a05eaca5676a6da Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Tue, 2 Apr 2024 17:06:22 +0200 Subject: [PATCH 082/156] Add an operator and basic types exercise for the first day. This is an attempt at deepening the understanding of type promotions and operators for basic types. This should address most of the ideas in issue #157. Fix #157 --- exercises/basicTypes/CMakeLists.txt | 15 ++++ exercises/basicTypes/Makefile | 11 +++ exercises/basicTypes/PrintHelper.h | 33 ++++++++ exercises/basicTypes/basicTypes.cpp | 79 ++++++++++++++++++ .../basicTypes/solution/basicTypes.sol.cpp | 81 +++++++++++++++++++ 5 files changed, 219 insertions(+) create mode 100644 exercises/basicTypes/CMakeLists.txt create mode 100644 exercises/basicTypes/Makefile create mode 100644 exercises/basicTypes/PrintHelper.h create mode 100644 exercises/basicTypes/basicTypes.cpp create mode 100644 exercises/basicTypes/solution/basicTypes.sol.cpp diff --git a/exercises/basicTypes/CMakeLists.txt b/exercises/basicTypes/CMakeLists.txt new file mode 100644 index 00000000..16b2d5c8 --- /dev/null +++ b/exercises/basicTypes/CMakeLists.txt @@ -0,0 +1,15 @@ +# Set up the project. +cmake_minimum_required( VERSION 3.12 ) +project( basicTypes LANGUAGES CXX ) + +# Set up the compilation environment. +include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) +set( CMAKE_CXX_STANDARD 20 ) + +# Create the user's executable. +add_executable( basicTypes PrintHelper.h basicTypes.cpp ) + +# Create the "solution executable". +add_executable( basicTypes.sol EXCLUDE_FROM_ALL PrintHelper.h solution/basicTypes.sol.cpp ) +target_include_directories( basicTypes.sol PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ) +add_dependencies( solution basicTypes.sol ) diff --git a/exercises/basicTypes/Makefile b/exercises/basicTypes/Makefile new file mode 100644 index 00000000..285197b9 --- /dev/null +++ b/exercises/basicTypes/Makefile @@ -0,0 +1,11 @@ +all: basicTypes +solution: basicTypes.sol + +clean: + rm -f *o *so basicTypes *~ basicTypes.sol + +% : %.cpp PrintHelper.h + $(CXX) -g -std=c++20 -Wall -Wextra -o $@ $< + +%.sol : solution/%.sol.cpp PrintHelper.h + $(CXX) -g -std=c++20 -Wall -Wextra -o $@ $< -I . diff --git a/exercises/basicTypes/PrintHelper.h b/exercises/basicTypes/PrintHelper.h new file mode 100644 index 00000000..073729bc --- /dev/null +++ b/exercises/basicTypes/PrintHelper.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include +#include + +#ifdef _MSC_VER +std::string demangle(std::string_view input) { return std::string{input}; } +#else +#include +std::string demangle(std::string_view input) { + int status; + return abi::__cxa_demangle(input.data(), NULL, NULL, &status); +} +#endif + +// This helper prints type and value of an expression +void printWithTypeInfo(std::string expression, auto const & t, bool useBitset = false) { + const auto & ti = typeid(t); + const std::string realname = demangle(ti.name()); + + std::cout << std::left << std::setw(30) << expression << " type=" << std::setw(20) << realname << "value="; + if (useBitset) { + std::cout << std::bitset<16>(t) << "\n"; + } else { + std::cout << std::setprecision(25) << t << "\n"; + } +} + +// This macro both prints and evaluates an expression: +#define print(A) printWithTypeInfo("Line " + std::to_string(__LINE__) + ": "#A, A); +#define printBinary(A) printWithTypeInfo("Line " + std::to_string(__LINE__) + ": "#A, A, true); diff --git a/exercises/basicTypes/basicTypes.cpp b/exercises/basicTypes/basicTypes.cpp new file mode 100644 index 00000000..3a46116b --- /dev/null +++ b/exercises/basicTypes/basicTypes.cpp @@ -0,0 +1,79 @@ +#include "PrintHelper.h" + +/* ************************************* + * * Fundamental types and expressions * + * ************************************* + * + * Tasks: + * ------ + * - Compile the program and analyse the output of the different expressions + * - Discuss with other students or your tutor in case the result of an expression is a surprise + * - Fix the marked expressions by changing types such that they produce meaningful results + * - Answer the questions in the code + */ + +int main() { + std::cout << "Using literals of different number types:\n"; + print(5); + print(5/2); //FIXME + print(100/2ull); + print(2 + 4ull); + print(2.f + 4ull); + print(0u - 1u); // FIXME + print(1.0000000001f); // FIXME Why is this number not represented correctly? + print(1. + 1.E-18); // FIXME + + std::cout << "\nUsing increment and decrement operators:\n"; + int a = 1; + int b; + int c; + print(b = a++); // Q: What is the difference between a++ and ++a? + print(c = ++a); + print(a); + print(b); + print(c); + + std::cout << "\nCompound assignment operators:\n"; + int n = 1; + print(n *= 2); // Q: Is there a difference between this and the next line? + print(n *= 2.9); + print(n -= 1.1f); + print(n /= 4); // Q: Based on the results of these expressions, is there a better type to be used for n? + + std::cout << "\nLogic expressions:\n"; + const bool alwaysTrue = true; + bool condition1 = false; + bool condition2 = true; + print( alwaysTrue && condition1 && condition2 ); + print( alwaysTrue || condition1 && condition2 ); // Q: Why does operator precedence render this expression useless? + print( alwaysTrue && condition1 || condition2 ); + print(condition1 != condition1); // Q: What is the difference between this and the following expression? + print(condition2 = !condition2); + print( alwaysTrue && condition1 && condition2 ); + print( alwaysTrue || condition1 && condition2 ); + print( alwaysTrue && condition1 || condition2 ); + + std::cout << '\n'; + print( false || 0b10 ); // Q: What is the difference between || and | ? + print( false | 0b10 ); + printBinary( 0b1 & 0b10 ); + printBinary( 0b1 | 0b10 ); + printBinary( 0b1 && 0b10 ); // Q: Are the operators && and || appropriate for integer types? + printBinary( 0b1 || 0b10 ); + + std::cout << "\nPlay with characters and strings:\n"; + print("a"); // Q: Why is this expression two bytes at run time, the next only one? + print('a'); + + char charArray[20]; + char* charPtr = charArray; + charArray[19] = 0; // Make sure that our string is terminated with the null byte + + print(charArray); + print(charArray[0] = 'a'); + print(charArray); + print(charArray[1] = 98); + print(charArray); + print(charPtr); + // FIXME: Ensure that no unexpected garbage is printed above +} diff --git a/exercises/basicTypes/solution/basicTypes.sol.cpp b/exercises/basicTypes/solution/basicTypes.sol.cpp new file mode 100644 index 00000000..f8b94551 --- /dev/null +++ b/exercises/basicTypes/solution/basicTypes.sol.cpp @@ -0,0 +1,81 @@ +#include "PrintHelper.h" + +/* ************************************* + * * Fundamental types and expressions * + * ************************************* + * + * Tasks: + * - Compile the program and analyse the output of the different expressions + * - Discuss with other students or your tutor in case the result of an expression is a surprise + * - Fix the marked expressions by changing types such that they produce meaningful results + * - Answer the questions in the code + */ + +int main() { + std::cout << "Using literals of different number types:\n"; + print(5); + print(5/2.); //FIXME + print(100/2ull); + print(2 + 4ull); + print(2.f + 4ull); + print(0 - 1 ); // FIXME + print(1.0000000001 ); // FIXME Why is this number not represented correctly? + print(1.l+ 1.E-18); // FIXME + + std::cout << "\nUsing increment and decrement operators:\n"; + int a = 1; + int b; + int c; + print(b = a++); // Q: What is the difference between a++ and ++a? + print(c = ++a); // A: Whether it returns the previous or new value + print(a); + print(b); + print(c); + + std::cout << "\nCompound assignment operators:\n"; + float n = 1; + print(n *= 2); // Q: Is there a difference between this and the next line? + print(n *= 2.9); // A: Yes, the computation runs in float and is converted back to int + print(n -= 1.1f); + print(n /= 4); // Q: Based on the results of these expressions, is there a better type to be used for n? + // A: Probably yes, for example float + + std::cout << "\nLogic expressions:\n"; + const bool alwaysTrue = true; + bool condition1 = false; + bool condition2 = true; + print( alwaysTrue && condition1 && condition2 ); + print( alwaysTrue || condition1 && condition2 ); // Q: Why does operator precedence render this expression useless? + print( alwaysTrue && condition1 || condition2 ); // A: "true || " is evaluated last. The expression therefore is always true. + print(condition1 != condition1); // Q: What is the difference between this and the following expression? + print(condition2 = !condition2); // A: The first is a comparison, the second a negation with subsequent assignment + print( alwaysTrue && condition1 && condition2 ); + print( alwaysTrue || condition1 && condition2 ); + print( alwaysTrue && condition1 || condition2 ); + + std::cout << '\n'; + print( false || 0b10 ); // Q: What is the difference between || and | ? + print( false | 0b10 ); // A: a boolean operation vs. a bit-wise boolean operation + printBinary( 0b1 & 0b10 ); + printBinary( 0b1 | 0b10 ); + printBinary( 0b1 && 0b10 ); // Q: Are the operators && and || appropriate for integer types? + printBinary( 0b1 || 0b10 ); // A: Most likely not, because the integers are first converted to boolean + + std::cout << "\nPlay with characters and strings:\n"; + print("a"); // Q: Why is this expression two bytes at run time, the next only one? + print('a'); // A: Because the first one is a string, which is 0-terminated + + char charArray[20]; + // There are many ways to solve this, for example to use std::string and not manually manage the memory. + // However, if one really desires to manage a char array, one should at least initialise it with the 0 byte: + std::fill(std::begin(charArray), std::end(charArray), '\0'); + char* charPtr = charArray; + + print(charArray); + print(charArray[0] = 'a'); + print(charArray); + print(charArray[1] = 98); + print(charArray); + print(charPtr); + // FIXME: Ensure that no unexpected garbage is printed above +} From 54c7fbf46de03582f5bbbb2932ddb47096a317d0 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Tue, 2 Apr 2024 17:10:07 +0200 Subject: [PATCH 083/156] Add basicTypes exercise to CI. --- .github/workflows/build-exercises.yml | 1 + exercises/CMakeLists.txt | 1 + exercises/Makefile | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-exercises.yml b/.github/workflows/build-exercises.yml index 42ef554c..8ca581e0 100644 --- a/.github/workflows/build-exercises.yml +++ b/.github/workflows/build-exercises.yml @@ -22,6 +22,7 @@ jobs: EXERCISE: - NAME: "asan" - NAME: "atomic" + - NAME: "basicTypes" - NAME: "callgrind" - NAME: "concepts" - NAME: "condition_variable" diff --git a/exercises/CMakeLists.txt b/exercises/CMakeLists.txt index bfb2cb5b..36420d05 100644 --- a/exercises/CMakeLists.txt +++ b/exercises/CMakeLists.txt @@ -16,6 +16,7 @@ endif() add_subdirectory( hello ) add_subdirectory( asan ) add_subdirectory( atomic ) +add_subdirectory( basicTypes ) add_subdirectory( callgrind ) add_subdirectory( condition_variable ) add_subdirectory( constness ) diff --git a/exercises/Makefile b/exercises/Makefile index 229fc7b2..647e410b 100644 --- a/exercises/Makefile +++ b/exercises/Makefile @@ -1,5 +1,5 @@ TESTDIRS = callgrind cppcheck header_units control hello modules move python smartPointers templates virtual_inheritance \ - debug helgrind memcheck polymorphism race stl valgrind + debug helgrind memcheck polymorphism race stl valgrind basicTypes NOCOMPILETESTDIRS = constness solution: From 476d7db963fd30f4f825545e79e7a25a8df14c9a Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Tue, 2 Apr 2024 17:42:21 +0200 Subject: [PATCH 084/156] Add basic types exercise to cheat sheet and course schedule. --- exercises/ExerciseSchedule_EssentialCourse.md | 2 ++ exercises/ExercisesCheatSheet.md | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/exercises/ExerciseSchedule_EssentialCourse.md b/exercises/ExerciseSchedule_EssentialCourse.md index 548418f0..ab2899fd 100644 --- a/exercises/ExerciseSchedule_EssentialCourse.md +++ b/exercises/ExerciseSchedule_EssentialCourse.md @@ -12,6 +12,8 @@ Day 1 - Basics Exercises ### Hello World (directory: [`hello`](hello), [CheatSheet](ExercisesCheatSheet.md#hello-world-directory-hello)) +### Basic types (directory: [`basicTypes`](basicTypes), [CheatSheet](ExercisesCheatSheet.md#basic-types-directory-basictypes)) + ### Functions (directory: [`functions`](functions), [CheatSheet](ExercisesCheatSheet.md#functions-directory-functions)) ### Control Structures (directory: [`control`](control), [CheatSheet](ExercisesCheatSheet.md#control-structures-directory-control)) diff --git a/exercises/ExercisesCheatSheet.md b/exercises/ExercisesCheatSheet.md index 42f3ad4c..fa8c268e 100644 --- a/exercises/ExercisesCheatSheet.md +++ b/exercises/ExercisesCheatSheet.md @@ -12,6 +12,10 @@ Basics Exercises Just try to compile and run `./hello` to make sure that everything is set up correctly. +### Basic types (directory: [`basicTypes`](basicTypes)) + +The goal is to observe the behaviour of a few basic types, correctly employ integer and floating-point literals, and to be aware of conversions and the effect of operators in expressions with such types. + ### Functions (directory: [`functions`](functions)) pass by copy / pass by reference From 130965de7a90738da3102b3962c5a50319896b9a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 7 May 2024 11:18:00 -0400 Subject: [PATCH 085/156] [pre-commit.ci] pre-commit autoupdate (#519) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v4.5.0 → v4.6.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.5.0...v4.6.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 29b16151..c8b15804 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v4.6.0 hooks: - id: check-added-large-files - id: check-case-conflict From 2c5034f09b1993e3ac764fa98c5980746eb1bb87 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Wed, 21 Aug 2024 16:05:45 +0200 Subject: [PATCH 086/156] Remove confusing statements from lambda slides. --- talk/morelanguage/lambda.tex | 58 ++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 32 deletions(-) diff --git a/talk/morelanguage/lambda.tex b/talk/morelanguage/lambda.tex index 63c89b0e..49a3a0db 100644 --- a/talk/morelanguage/lambda.tex +++ b/talk/morelanguage/lambda.tex @@ -1,32 +1,5 @@ \subsection[$\lambda$]{Lambdas} -\begin{frame}[fragile] - \frametitlecpp[11]{Trailing function return type} - \begin{block}{An alternate way to specify a function's return type} - \begin{cppcode*}{linenos=false} - int f(float a); // classic - auto f(float a) -> int; // trailing - auto f(float a) { return 42; } // deduced, C++14 - \end{cppcode*} - \end{block} - \pause - \begin{block}{Advantages} - \begin{itemize} - \item Allows to simplify inner type definition - \begin{cppcode*}{gobble=4} - class Equation { - using ResultType = double; - ResultType evaluate(); - } - Equation::ResultType Equation::evaluate() {...} - auto Equation::evaluate() -> ResultType {...} - \end{cppcode*} - \item Used by lambda expressions - \end{itemize} - \end{block} -\end{frame} - - \begin{frame}[fragile] \frametitlecpp[11]{Lambda expressions} \begin{block}{Definition} @@ -72,6 +45,31 @@ \end{exampleblock} \end{frame} +\begin{frame}[fragile] + \frametitlecpp[11]{Trailing function return type} + \begin{block}{An alternate way to specify a function's return type} + \begin{cppcode*}{linenos=false} + int f(float a); // classic + auto f(float a) -> int; // trailing + auto f(float a) { return 42; } // deduced, C++14 + \end{cppcode*} + \end{block} + \pause + \begin{block}{When to use trailing return type} + \begin{itemize} + \item Only way to specify return type for lambdas + \item Allows to simplify inner type definition + \begin{cppcode*}{gobble=4} + class Equation { + using ResultType = double; + ResultType evaluate(); + } + Equation::ResultType Equation::evaluate() {...} + auto Equation::evaluate() -> ResultType {...} + \end{cppcode*} + \end{itemize} + \end{block} +\end{frame} \begin{frame}[fragile] \frametitlecpp[11]{Capturing variables} @@ -143,7 +141,7 @@ \begin{block}{Explanation} \begin{itemize} \item By default, variables are captured by value - \item The lambda's \cppinline{operator()} is \cppinline{const} + \item The lambda's \cppinline{operator()} is \cppinline{const inline} \end{itemize} \end{block} \end{frame} @@ -339,10 +337,6 @@ } s; s.f(42); // prints "42" - template - using CudaPtr = std::unique_ptr; - std::set s2; \end{cppcode*} \end{exampleblock} From 7dd6e30dd0e10d8ba14816fb92768c143a39f0b8 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Wed, 21 Aug 2024 16:06:22 +0200 Subject: [PATCH 087/156] Use const for span demos. We tell students to extensively use const, but the spans demo would have allowed changing values in the original containers. Fix #352 --- talk/morelanguage/morestl.tex | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/talk/morelanguage/morestl.tex b/talk/morelanguage/morestl.tex index a407b975..0c6358cf 100644 --- a/talk/morelanguage/morestl.tex +++ b/talk/morelanguage/morestl.tex @@ -56,10 +56,10 @@ \begin{frame}[fragile] \frametitlecpp[20]{\texttt{std::span} - Usage} - \begin{exampleblockGB}{Some example}{https://godbolt.org/z/bTWjM8ba1}{\texttt{span}} + \begin{exampleblockGB}{Some example}{https://godbolt.org/z/nP3jr388z}{\texttt{span}} \scriptsize \begin{cppcode*}{} - void print(std::span c) { + void print(std::span c) { for (auto a : c) { std::cout << a << " "; } std::cout << "\n"; } @@ -70,16 +70,16 @@ print(a); // 23 45 67 89 std::vector v{1, 2, 3, 4, 5}; - std::span sv = v; + std::span sv = v; print(sv.subspan(2, 2)); // 3 4 std::array a2{-14, 55, 24}; times2(a2); print(a2); // -28 110 48 - std::span sa2 = a2; + std::span sa2 = a2; std::cout << sizeof(sv) << " " << sizeof(sa2) << "\n"; // 16 8 - std::span s2a2 = a; // compilation failure, invalid conversion + std::span s2a2 = a; // compilation failure, invalid conversion \end{cppcode*} \end{exampleblockGB} \end{frame} From c9c2da2f8e8af9d55b564734e4711f62886e541c Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Wed, 21 Aug 2024 16:15:32 +0200 Subject: [PATCH 088/156] Remove statement about godbolt tools that don't exist. --- talk/tools/webtools.tex | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/talk/tools/webtools.tex b/talk/tools/webtools.tex index b8835fa2..6f26b262 100644 --- a/talk/tools/webtools.tex +++ b/talk/tools/webtools.tex @@ -6,11 +6,10 @@ An online generic compiler with immediate feedback. Allows: \begin{itemize} - \item compiling online any code against any version of any compiler + \item trying various compilers in the browser \item inspecting the assembly generated \item use of external libraries (over 50 available !) - \item running the code produced - \item using tools, e.g. ldd, include-what-you-use, ... + \item running the produced code \item sharing small pieces of code via permanent short links \end{itemize} \end{block} From eda78a3c0148879c744988afa114f55cb7af761a Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Wed, 21 Aug 2024 17:52:17 +0200 Subject: [PATCH 089/156] Simplify example in ADL slides. The example was mentioned to be difficult to read. Fix #352. --- talk/objectorientation/adl.tex | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/talk/objectorientation/adl.tex b/talk/objectorientation/adl.tex index b44161ac..08c430f4 100644 --- a/talk/objectorientation/adl.tex +++ b/talk/objectorientation/adl.tex @@ -171,20 +171,36 @@ \item Avoid accidental implicit conversions \end{itemize} \end{block} - \begin{alertblock}{Accidental conversions - two examples in one} + \begin{alertblock}{Accidental conversions - two counterexamples} \footnotesize + \begin{overprint} + \onslide<1> \begin{cppcode*}{gobble=2} std::ostream & operator<< // out-of-class definition (std::ostream & os, Complex const & c) { ... } struct Fraction { int num, denom; - operator Complex() const { ... } // case 1: conversion op + operator Complex() const { ... } // conversion op }; - Complex::Complex(Fraction f); // or case 2: converting ctor - std::cout << Fraction{2,4}; // Prints 0.5 + 0i, would call: - //case 1: operator<<(std::cout, Fraction{2,4}.operator Complex()); - //case 2: operator<<(std::cout, Complex(Fraction{2, 3})); + + std::cout << Fraction{2,4}; // Prints 0.5 + 0i + //calls operator<<(std::cout, Fraction{2,4}.operator Complex()); + \end{cppcode*} + + \onslide<2> + \begin{cppcode*}{gobble=2} + std::ostream & operator<< // out-of-class definition + (std::ostream & os, Complex const & c) { ... } + struct Fraction { + int num, denom; + }; + + Complex::Complex(Fraction f); // converting ctor + + std::cout << Fraction{2,4}; // Prints 0.5 + 0i + //calls operator<<(std::cout, Complex(Fraction{2, 3})); \end{cppcode*} + \end{overprint} \end{alertblock} \end{frame} From 7de04a8d97d4139d3f2132543a4e481367661730 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Wed, 21 Aug 2024 17:53:03 +0200 Subject: [PATCH 090/156] Mention that most IDEs support clang-format. Co-authored-by: Sebastien Ponce --- talk/tools/formatting.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/talk/tools/formatting.tex b/talk/tools/formatting.tex index 04f9e808..789bb149 100644 --- a/talk/tools/formatting.tex +++ b/talk/tools/formatting.tex @@ -17,7 +17,7 @@ \item \mintinline{bash}{clang-format -i } (looks for .clang-format file) \item \mintinline{bash}{git clang-format} (formats local changes) \item \mintinline{bash}{git clang-format } (formats changes since git \textless{}ref\textgreater{}) - \item Some editors/IDEs find a .clang-format file and adapt + \item Most editors/IDEs can find a .clang-format file and adapt \end{itemize} \end{block} \end{frame} From ccdf0fbc406a454e66a6411c6181c8f03f9d4d7e Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Wed, 21 Aug 2024 17:54:01 +0200 Subject: [PATCH 091/156] Small updates to concurrency. - Slightly reword a few sentences. - Fit bullet points in a single line. --- talk/concurrency/condition.tex | 16 +++++++++------- talk/concurrency/mutexes.tex | 4 ++-- talk/concurrency/threadlocal.tex | 9 +++++---- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/talk/concurrency/condition.tex b/talk/concurrency/condition.tex index c2182214..86c1be82 100644 --- a/talk/concurrency/condition.tex +++ b/talk/concurrency/condition.tex @@ -60,20 +60,22 @@ \onslide<1> \begin{block}{Mechanics of wait} \begin{itemize} - \item Many threads are waiting for shared data - \item Pass a \cppinline{unique_lock} and a predicate for wakeup to \cppinline{wait()} - \item \cppinline{wait()} sends threads to sleep while predicate is \cppinline{false} + \item Many threads can wait for shared data + \item Pass \cppinline{unique_lock} and optional predicate to \cppinline{wait()} + \item \cppinline{wait()} keeps threads asleep while predicate is \cppinline{false} + \begin{itemize} + \item Threads might wake up spuriously, but \cppinline{wait()} returns only when lock available \emph{and} predicate \cppinline{true} + \end{itemize} \item \cppinline{wait()} will only lock when necessary; unlocked while sleeping - \item Threads might wake up spuriously, but \cppinline{wait()} returns only when lock available \emph{and} predicate \cppinline{true} \end{itemize} \end{block} \onslide<2-> \begin{block}{Waiting / waking up} \begin{itemize} - \item \cppinline{notify_all()} is called, threads wake up + \item When \cppinline{notify_all()} is called, threads wake up \item Threads try to lock mutex, and evaluate predicate - \item One thread succeeds to acquire mutex, starts data processing - \item {\color{red} Problem}: Thread holds mutex now, other threads are blocked! + \item One thread succeeds to acquire mutex, starts processing data + \item {\color{red} Problem}: One thread holds mutex, other threads are blocked! \end{itemize} \end{block} \end{overprint} diff --git a/talk/concurrency/mutexes.tex b/talk/concurrency/mutexes.tex index b6bb3dd6..d190e0aa 100644 --- a/talk/concurrency/mutexes.tex +++ b/talk/concurrency/mutexes.tex @@ -230,8 +230,8 @@ \frametitlecpp[20]{Synchronised \texttt{cout}} \begin{block}{Parallel writing to streams} \begin{itemize} - \item All parallel writes to streams become garbled when not synchronised - \item \cppinline{std::osyncstream} is a wrapper to synchronise output to streams + \item Parallel writes to streams become garbled when not synchronised + \item \cppinline{std::osyncstream} wraps and synchronises output to streams \item Multiple instances of the osyncstream synchronise globally \end{itemize} \end{block} diff --git a/talk/concurrency/threadlocal.tex b/talk/concurrency/threadlocal.tex index 64bbe570..0473a91f 100644 --- a/talk/concurrency/threadlocal.tex +++ b/talk/concurrency/threadlocal.tex @@ -16,10 +16,11 @@ \begin{exampleblock}{} \begin{cppcode*}{} thread_local int a{0}; - std::jthread t1([&] { a++; }); - std::jthread t2([&] { a++; }); - a += 2; - t1.join(); t2.join(); + { + std::jthread t1([&] { a++; }); + std::jthread t2([&] { a++; }); + a += 2; + } assert( a == 2 ); // Guaranteed to succeed \end{cppcode*} \end{exampleblock} From e0d5baccc2f82ed067fb4fc2c28050160c177df3 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Wed, 21 Aug 2024 17:55:06 +0200 Subject: [PATCH 092/156] Add a README to basicTypes exercise. --- exercises/basicTypes/README.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 exercises/basicTypes/README.md diff --git a/exercises/basicTypes/README.md b/exercises/basicTypes/README.md new file mode 100644 index 00000000..132a0a6e --- /dev/null +++ b/exercises/basicTypes/README.md @@ -0,0 +1,7 @@ +# Fundamental types and expressions + +## Tasks: +- Compile the program and analyse the output of the different expressions +- Discuss with other students or your tutor in case the result of an expression is a surprise +- Fix the marked expressions by changing types such that they produce meaningful results +- Answer the questions in the code From 29df93476a6d0fdbde831ad481d321b7c963b366 Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Thu, 22 Aug 2024 10:10:29 +0200 Subject: [PATCH 093/156] Added 2 slides on timing at the end of MoreSTL section --- talk/morelanguage/morestl.tex | 56 +++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/talk/morelanguage/morestl.tex b/talk/morelanguage/morestl.tex index 0c6358cf..8fcb7965 100644 --- a/talk/morelanguage/morestl.tex +++ b/talk/morelanguage/morestl.tex @@ -424,3 +424,59 @@ \end{cppcode*} \end{exampleblock} \end{frame} + +\begin{frame}[fragile] + \frametitle{\cpp date and time utilities \hfill \cpp11 / \cpp20} + \cppinline{std::chrono library} present in \cppinline{} header + \begin{block}{Clocks} + \begin{itemize} + \item consists of a starting point (or epoch) and a tick rate + \begin{itemize} + \item E.g. January 1, 1970 and every second + \end{itemize} + \item C++ defines several clock type + \begin{itemize} + \item \href{https://en.cppreference.com/w/cpp/chrono/system_clock}{\color{blue!50!white} \cppinline{system_clock}} system time, aka wall clock time, or C time + \item \href{https://en.cppreference.com/w/cpp/chrono/steady_clock}{\color{blue!50!white} \cppinline{steady_clock}} monotonic but unrelated to wall clock time + \item \href{https://en.cppreference.com/w/cpp/chrono/high_resolution_clock}{\color{blue!50!white} \cppinline{high_resolution_clock}} clock with the smallest tick period + \end{itemize} + \end{itemize} + \end{block} + \begin{block}{\href{https://en.cppreference.com/w/cpp/chrono/time_point}{\color{blue!50!white} \cppinline{time_point}} and \href{https://en.cppreference.com/w/cpp/chrono/duration}{\color{blue!50!white} \cppinline{duration}}} + \begin{itemize} + \item provide easy manipulation of times and duration + \item clock dependent + \item \href{https://en.cppreference.com/w/cpp/chrono/duration/duration_cast}{\color{blue!50!white} \cppinline{duration_cast}} allows conversions between duration types + \begin{itemize} + \item available helper types : nanoseconds, microseconds, milliseconds, seconds, minutes, hours, ... + \end{itemize} + \end{itemize} + \end{block} +\end{frame} + +\begin{frame}[fragile] + \frametitlecpp[11]{Practical usage / timing some \cpp code} + \begin{exampleblockGB}{How to measure the time spent in some code}{https://godbolt.org/z/PzKWer5eb}{\texttt{timing}} + \small + \begin{cppcode*}{gobble=2} + #include + + std::chrono::high_resolution_clock clock; + auto start = clock::now(); + ... // code to be timed + std::chrono::duration ticks = clock.now() - start; + + auto millis = std::chrono::duration_cast + (ticks); + std::cout << "it took " << ticks.count() << " ticks" + << ", that is " << millis.count() << " ms\n"; + \end{cppcode*} + \end{exampleblockGB} + \pause + \begin{alertblock}{Warning} + \begin{itemize} + \item this does not measure the amount of CPU used ! + \item neither the time spent on a CPU (think suspended threads) + \end{itemize} + \end{alertblock} +\end{frame} From 2b52aaece2f742bc8aa42e5718988de0c38e3778 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 21:36:48 +0000 Subject: [PATCH 094/156] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/codespell-project/codespell: v2.2.6 → v2.3.0](https://github.com/codespell-project/codespell/compare/v2.2.6...v2.3.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c8b15804..8df4a34f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/codespell-project/codespell - rev: 'v2.2.6' + rev: 'v2.3.0' hooks: - id: codespell args: ["-I", "codespell.txt"] From 9f1b599b300c1ba86ac9b9a90171122c34b98fa1 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Wed, 18 Sep 2024 17:59:34 +0200 Subject: [PATCH 095/156] [Advanced] Add a marker on advanced slides. It can be difficult to tell the difference between the advanced and essentials slides based on the colour. Here, we add a little "Adv" in the top right corner. --- talk/C++Course.tex | 2 ++ talk/setup.tex | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/talk/C++Course.tex b/talk/C++Course.tex index bb06acbc..88767298 100644 --- a/talk/C++Course.tex +++ b/talk/C++Course.tex @@ -28,8 +28,10 @@ % advanced slides have a different structure color \specialcomment{advanced}{ \setbeamercolor{structure}{fg=beamer@blendedblue!40!violet} + \isAdvancedSlidetrue }{ \setbeamercolor{structure}{fg=beamer@blendedblue} + \isAdvancedSlidefalse } \fi diff --git a/talk/setup.tex b/talk/setup.tex index 2b30ee3d..a416f16b 100644 --- a/talk/setup.tex +++ b/talk/setup.tex @@ -188,9 +188,15 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % frametitle with C++ version % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Switch designs for advanced and essentials course: +\newif\ifisAdvancedSlide\isAdvancedSlidefalse % Use as \frametitlecpp[14]{Title} \newcommand\frametitlecpp[2][98]{ - \frametitle{#2 \hfill \cpp#1} + \ifisAdvancedSlide + \frametitle{#2 \hfill \cpp#1 \small Adv} + \else + \frametitle{#2 \hfill \cpp#1} + \fi } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% From e1d16b92823342d82e33c2a974a8d12b6cf95721 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Wed, 18 Sep 2024 18:14:00 +0200 Subject: [PATCH 096/156] Fix typos pointed out by CI. --- exercises/ExerciseSchedule_AdvancedCourse.md | 2 +- talk/objectorientation/constructors.tex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/ExerciseSchedule_AdvancedCourse.md b/exercises/ExerciseSchedule_AdvancedCourse.md index 071685da..4c3da299 100644 --- a/exercises/ExerciseSchedule_AdvancedCourse.md +++ b/exercises/ExerciseSchedule_AdvancedCourse.md @@ -5,7 +5,7 @@ HEP C++ Advanced Course's exercise schedule - Solutions and hints can be found in the ExercisesCheatSheet.md file located in the same directory. - Each exercise is in its own directory and referred to in the following by the name of the directory -There are far too many exercies on each day. They are given in order in which they should be done. +There are far too many exercises on each day. They are given in order in which they should be done. Day 1 ----- diff --git a/talk/objectorientation/constructors.tex b/talk/objectorientation/constructors.tex index b719732a..f9c994c4 100644 --- a/talk/objectorientation/constructors.tex +++ b/talk/objectorientation/constructors.tex @@ -216,7 +216,7 @@ \frametitlecpp[11]{Constructor inheritance} \begin{block}{Idea} \begin{itemize} - \item avoid having to re-declare parent's constructors + \item avoid having to redeclare parent's constructors \item by stating that we inherit all parent constructors \item derived class can add more constructors \end{itemize} From 856b680d7a3b9d68a7b9129c7a947bd023e740ab Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Thu, 19 Sep 2024 17:03:10 +0200 Subject: [PATCH 097/156] Renamed chapter 'More STL' to 'standard library' --- talk/morelanguage/morestl.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/talk/morelanguage/morestl.tex b/talk/morelanguage/morestl.tex index 8fcb7965..bb277474 100644 --- a/talk/morelanguage/morestl.tex +++ b/talk/morelanguage/morestl.tex @@ -1,4 +1,4 @@ -\subsection[More]{More STL} +\subsection[STD]{Standard library} \begin{frame}[fragile] \frametitlecpp[17]{\texttt{std::string\_view} \cpprefLink{https://en.cppreference.com/w/cpp/string/basic_string_view}} From 03e9583880981d0401ca634e6b248d728e9acacb Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Thu, 19 Sep 2024 17:03:52 +0200 Subject: [PATCH 098/156] Added godbold link for the last lambda example --- talk/morelanguage/lambda.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/talk/morelanguage/lambda.tex b/talk/morelanguage/lambda.tex index 49a3a0db..168fc295 100644 --- a/talk/morelanguage/lambda.tex +++ b/talk/morelanguage/lambda.tex @@ -329,7 +329,7 @@ \item Without captures, are default-constructible and assignable \end{itemize} \end{block} - \begin{exampleblock}{Examples} + \begin{exampleblockGB}{Example}{https://godbolt.org/z/GoE6xM8EG}{\texttt{lambda \cpp20}} \small \begin{cppcode*}{gobble=2} struct S { @@ -339,7 +339,7 @@ std::set s2; \end{cppcode*} - \end{exampleblock} + \end{exampleblockGB} \end{frame} From faa6cdbc57ad1a41be30c71cb972dc9736b7d822 Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Fri, 20 Sep 2024 14:38:15 +0200 Subject: [PATCH 099/156] Fixed issues with highlighting, scontent and minted This is a poor fix where code is replicated n times. I did not manage to do better. Any good idea is welcome. But take care, it's a tricky case due to the verbatim status of minted --- talk/basicconcepts/arrayspointers.tex | 168 +++++++++++++++++++-- talk/basicconcepts/functions.tex | 187 ++++++++++++++++++++---- talk/basicconcepts/scopesnamespaces.tex | 51 +++++-- talk/setup.tex | 16 -- 4 files changed, 353 insertions(+), 69 deletions(-) diff --git a/talk/basicconcepts/arrayspointers.tex b/talk/basicconcepts/arrayspointers.tex index 5cc2d69b..7a6c4edd 100644 --- a/talk/basicconcepts/arrayspointers.tex +++ b/talk/basicconcepts/arrayspointers.tex @@ -16,7 +16,14 @@ \end{cppcode} \end{frame} -\Scontents*[store-cmd=code_arrays]{ +\begin{frame}[fragile] + \frametitlecpp[98]{Pointers} + \begin{multicols}{2} + % the code has to be repeated n times here. Anyone finding a better solution + % is welcome, but it's not a trivial task, due to the verbatim nature of minted + \begin{overprint}[\columnwidth] + \onslide<1> + \begin{minted}[linenos]{cpp} int i = 4; int *pi = &i; int j = *pi + 1; @@ -32,20 +39,151 @@ // seg fault ! int *pak = (int*)k; int l = *pak; -} -\begin{frame}[fragile] - \frametitlecpp[98]{Pointers} - \begin{multicols}{2} - \begin{overprint}[\columnwidth] - \onslide<1> \highlightCppCode{}{code_arrays} - \onslide<2> \highlightCppCode{1}{code_arrays} - \onslide<3> \highlightCppCode{2}{code_arrays} - \onslide<4> \highlightCppCode{3}{code_arrays} - \onslide<5> \highlightCppCode{5}{code_arrays} - \onslide<6> \highlightCppCode{6}{code_arrays} - \onslide<7> \highlightCppCode{7}{code_arrays} - \onslide<8> \highlightCppCode{8}{code_arrays} - \onslide<9> \highlightCppCode{11}{code_arrays} + \end{minted} + \onslide<2> + \begin{minted}[linenos,highlightlines=1]{cpp} +int i = 4; +int *pi = &i; +int j = *pi + 1; + +int ai[] = {1,2,3}; +int *pai = ai; // decay to ptr +int *paj = pai + 1; +int k = *paj + 1; + +// compile error +int *pak = k; + +// seg fault ! +int *pak = (int*)k; +int l = *pak; + \end{minted} + \onslide<3> + \begin{minted}[linenos,highlightlines=2]{cpp} +int i = 4; +int *pi = &i; +int j = *pi + 1; + +int ai[] = {1,2,3}; +int *pai = ai; // decay to ptr +int *paj = pai + 1; +int k = *paj + 1; + +// compile error +int *pak = k; + +// seg fault ! +int *pak = (int*)k; +int l = *pak; + \end{minted} + \onslide<4> + \begin{minted}[linenos,highlightlines=3]{cpp} +int i = 4; +int *pi = &i; +int j = *pi + 1; + +int ai[] = {1,2,3}; +int *pai = ai; // decay to ptr +int *paj = pai + 1; +int k = *paj + 1; + +// compile error +int *pak = k; + +// seg fault ! +int *pak = (int*)k; +int l = *pak; + \end{minted} + \onslide<5> + \begin{minted}[linenos,highlightlines=5]{cpp} +int i = 4; +int *pi = &i; +int j = *pi + 1; + +int ai[] = {1,2,3}; +int *pai = ai; // decay to ptr +int *paj = pai + 1; +int k = *paj + 1; + +// compile error +int *pak = k; + +// seg fault ! +int *pak = (int*)k; +int l = *pak; + \end{minted} + \onslide<6> + \begin{minted}[linenos,highlightlines=6]{cpp} +int i = 4; +int *pi = &i; +int j = *pi + 1; + +int ai[] = {1,2,3}; +int *pai = ai; // decay to ptr +int *paj = pai + 1; +int k = *paj + 1; + +// compile error +int *pak = k; + +// seg fault ! +int *pak = (int*)k; +int l = *pak; + \end{minted} + \onslide<7> + \begin{minted}[linenos,highlightlines=7]{cpp} +int i = 4; +int *pi = &i; +int j = *pi + 1; + +int ai[] = {1,2,3}; +int *pai = ai; // decay to ptr +int *paj = pai + 1; +int k = *paj + 1; + +// compile error +int *pak = k; + +// seg fault ! +int *pak = (int*)k; +int l = *pak; + \end{minted} + \onslide<8> + \begin{minted}[linenos,highlightlines=8]{cpp} +int i = 4; +int *pi = &i; +int j = *pi + 1; + +int ai[] = {1,2,3}; +int *pai = ai; // decay to ptr +int *paj = pai + 1; +int k = *paj + 1; + +// compile error +int *pak = k; + +// seg fault ! +int *pak = (int*)k; +int l = *pak; + \end{minted} + \onslide<9> + \begin{minted}[linenos,highlightlines=11]{cpp} +int i = 4; +int *pi = &i; +int j = *pi + 1; + +int ai[] = {1,2,3}; +int *pai = ai; // decay to ptr +int *paj = pai + 1; +int k = *paj + 1; + +// compile error +int *pak = k; + +// seg fault ! +int *pak = (int*)k; +int l = *pak; + \end{minted} \end{overprint} \columnbreak \onslide<2->{ diff --git a/talk/basicconcepts/functions.tex b/talk/basicconcepts/functions.tex index 218a6e72..24ea9f40 100644 --- a/talk/basicconcepts/functions.tex +++ b/talk/basicconcepts/functions.tex @@ -69,7 +69,14 @@ \end{frame} -\Scontents*[store-cmd=code_bigStruct]{ +\begin{frame}[fragile] + \frametitlecpp[98]{Functions: parameters are passed by value} + \begin{multicols}{2} + % the code has to be repeated n times here. Anyone finding a better solution + % is welcome, but it's not a trivial task, due to the verbatim nature of minted + \begin{overprint}[\columnwidth] + \onslide<1-2> + \begin{minted}[linenos,highlightlines=2]{cpp} struct BigStruct {...}; BigStruct s; @@ -84,17 +91,41 @@ ... } printRef(s); // no copy -} -\begin{frame}[fragile] - \frametitlecpp[98]{Functions: parameters are passed by value} - \begin{multicols}{2} - \begin{overprint}[\columnwidth] - \onslide<1-2> - \highlightCppCode{2}{code_bigStruct} + \end{minted} \onslide<3> - \highlightCppCode{5,8}{code_bigStruct} + \begin{minted}[linenos,highlightlines={5,8}]{cpp} +struct BigStruct {...}; +BigStruct s; + +// parameter by value +void printVal(BigStruct p) { + ... +} +printVal(s); // copy + +// parameter by reference +void printRef(BigStruct &q) { + ... +} +printRef(s); // no copy + \end{minted} \onslide<4-> - \highlightCppCode{11,14}{code_bigStruct} + \begin{minted}[linenos,highlightlines={11,14}]{cpp} +struct BigStruct {...}; +BigStruct s; + +// parameter by value +void printVal(BigStruct p) { + ... +} +printVal(s); // copy + +// parameter by reference +void printRef(BigStruct &q) { + ... +} +printRef(s); // no copy + \end{minted} \end{overprint} \columnbreak \null \vfill @@ -121,7 +152,14 @@ \end{multicols} \end{frame} -\Scontents*[store-cmd=code_smallStruct]{ +\begin{frame}[fragile] + \frametitlecpp[98]{Functions: pass by value or reference?} + \begin{multicols}{2} + % the code has to be repeated n times here. Anyone finding a better solution + % is welcome, but it's not a trivial task, due to the verbatim nature of minted + \begin{overprint}[\columnwidth] + \onslide<1> + \begin{minted}[linenos]{cpp} struct SmallStruct {int a;}; SmallStruct s = {1}; @@ -136,27 +174,126 @@ } changeRef(s); // s.a == 2 -} -\begin{frame}[fragile] - \frametitlecpp[98]{Functions: pass by value or reference?} - \begin{multicols}{2} - \begin{overprint}[\columnwidth] - \onslide<1> - \highlightCppCode{}{code_smallStruct} + \end{minted} \onslide<2> - \highlightCppCode{2}{code_smallStruct} + \begin{minted}[linenos,highlightlines=2]{cpp} +struct SmallStruct {int a;}; +SmallStruct s = {1}; + +void changeVal(SmallStruct p) { + p.a = 2; +} +changeVal(s); +// s.a == 1 + +void changeRef(SmallStruct &q) { + q.a = 2; +} +changeRef(s); +// s.a == 2 + \end{minted} \onslide<3> - \highlightCppCode{4,7}{code_smallStruct} + \begin{minted}[linenos,highlightlines={4,7}]{cpp} +struct SmallStruct {int a;}; +SmallStruct s = {1}; + +void changeVal(SmallStruct p) { + p.a = 2; +} +changeVal(s); +// s.a == 1 + +void changeRef(SmallStruct &q) { + q.a = 2; +} +changeRef(s); +// s.a == 2 + \end{minted} \onslide<4> - \highlightCppCode{5}{code_smallStruct} + \begin{minted}[linenos,highlightlines=5]{cpp} +struct SmallStruct {int a;}; +SmallStruct s = {1}; + +void changeVal(SmallStruct p) { + p.a = 2; +} +changeVal(s); +// s.a == 1 + +void changeRef(SmallStruct &q) { + q.a = 2; +} +changeRef(s); +// s.a == 2 + \end{minted} \onslide<5> - \highlightCppCode{8}{code_smallStruct} + \begin{minted}[linenos,highlightlines=8]{cpp} +struct SmallStruct {int a;}; +SmallStruct s = {1}; + +void changeVal(SmallStruct p) { + p.a = 2; +} +changeVal(s); +// s.a == 1 + +void changeRef(SmallStruct &q) { + q.a = 2; +} +changeRef(s); +// s.a == 2 + \end{minted} \onslide<6> - \highlightCppCode{10,13}{code_smallStruct} + \begin{minted}[linenos,highlightlines={10,13}]{cpp} +struct SmallStruct {int a;}; +SmallStruct s = {1}; + +void changeVal(SmallStruct p) { + p.a = 2; +} +changeVal(s); +// s.a == 1 + +void changeRef(SmallStruct &q) { + q.a = 2; +} +changeRef(s); +// s.a == 2 + \end{minted} \onslide<7> - \highlightCppCode{11}{code_smallStruct} + \begin{minted}[linenos,highlightlines=11]{cpp} +struct SmallStruct {int a;}; +SmallStruct s = {1}; + +void changeVal(SmallStruct p) { + p.a = 2; +} +changeVal(s); +// s.a == 1 + +void changeRef(SmallStruct &q) { + q.a = 2; +} +changeRef(s); +// s.a == 2 + \end{minted} \onslide<8> - \highlightCppCode{14}{code_smallStruct} + \begin{minted}[linenos,highlightlines=14]{cpp} +struct SmallStruct {int a;}; +SmallStruct s = {1}; + +void changeVal(SmallStruct p) { + p.a = 2; +} +changeVal(s); +// s.a == 1 + +void changeRef(SmallStruct &q) { + q.a = 2; +} +changeRef(s); +// s.a == 2 + \end{minted} \end{overprint} \columnbreak \null \vfill diff --git a/talk/basicconcepts/scopesnamespaces.tex b/talk/basicconcepts/scopesnamespaces.tex index d3995b79..a9abfab5 100644 --- a/talk/basicconcepts/scopesnamespaces.tex +++ b/talk/basicconcepts/scopesnamespaces.tex @@ -21,15 +21,6 @@ \end{exampleblock} \end{frame} -\Scontents*[store-cmd=code_scopes]{ -int a = 1; -{ - int b[4]; - b[0] = a; -} -// Doesn't compile here: -// b[1] = a + 1; -} \begin{frame}[fragile] \frametitlecpp[98]{Scope and lifetime of variables} \begin{block}{Variable life time} @@ -45,15 +36,49 @@ \end{itemize} \end{goodpractice} \begin{multicols}{2} + % the code has to be repeated n times here. Anyone finding a better solution + % is welcome, but it's not a trivial task, due to the verbatim nature of minted \begin{overprint}[\columnwidth] \onslide<1> - \highlightCppCode{1}{code_scopes} + \begin{minted}[linenos,highlightlines=1]{cpp} +int a = 1; +{ + int b[4]; + b[0] = a; +} +// Doesn't compile here: +// b[1] = a + 1; + \end{minted} \onslide<2> - \highlightCppCode{3}{code_scopes} + \begin{minted}[linenos,highlightlines=3]{cpp} +int a = 1; +{ + int b[4]; + b[0] = a; +} +// Doesn't compile here: +// b[1] = a + 1; + \end{minted} \onslide<3> - \highlightCppCode{4}{code_scopes} + \begin{minted}[linenos,highlightlines=4]{cpp} +int a = 1; +{ + int b[4]; + b[0] = a; +} +// Doesn't compile here: +// b[1] = a + 1; + \end{minted} \onslide<4> - \highlightCppCode{7}{code_scopes} + \begin{minted}[linenos,highlightlines=7]{cpp} +int a = 1; +{ + int b[4]; + b[0] = a; +} +// Doesn't compile here: +// b[1] = a + 1; + \end{minted} \end{overprint} \columnbreak diff --git a/talk/setup.tex b/talk/setup.tex index a416f16b..2318b1a1 100644 --- a/talk/setup.tex +++ b/talk/setup.tex @@ -49,24 +49,8 @@ \usepackage{morewrites} \usepackage[utf8]{inputenc} \usepackage{newunicodechar} -\usepackage{scontents} -\makeatletter -\let\verbatimsc\@undefined -\let\endverbatimsc\@undefined -\makeatother \usepackage{minted} \newminted{tex}{linenos} -\newenvironment{verbatimsc} - {\VerbatimEnvironment - \begin{minted}[linenos,escapeinside=||]{cpp}} - {\end{minted}} -\newcommand\highlightCppCode[2]{ - \renewenvironment{verbatimsc} - {\VerbatimEnvironment - \begin{minted}[linenos,highlightlines={#1},escapeinside=||]{cpp}} - {\end{minted}} - \typestored{#2} -} \newminted{cpp}{gobble=4,linenos} \newminted{shell-session}{gobble=4} \newminted[makefile]{shell-session}{gobble=4} From 8e770dd443eee6b4400481ec2544e820491a5ce3 Mon Sep 17 00:00:00 2001 From: Mosolov Sergei Date: Fri, 20 Sep 2024 17:55:06 +0400 Subject: [PATCH 100/156] Make explicit statement that C++ compiled "to native machine code" (#521) * Make explicit statement that C++ compiled "to native machine code" All main implementation of the languages in the example (Java, C# and Python) are actually compiled to bytecode. IMHO it's better to clearly add explicit statement that C++ is compiled "to native machine code" unlike this languages to avoid ambiguity. * Update talk/introduction/goals.tex --------- Co-authored-by: Sebastien Ponce --- talk/introduction/goals.tex | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/talk/introduction/goals.tex b/talk/introduction/goals.tex index 1991e0d7..d0ef26d3 100644 --- a/talk/introduction/goals.tex +++ b/talk/introduction/goals.tex @@ -13,7 +13,10 @@ \pause \begin{block}{Fast} \begin{itemize} - \item compiled (unlike Java, C\#, Python, ...) + \item compiled to native machine code + \begin{itemize} + \item unlike Java, C\#, Python, ... + \end{itemize} \item allows to go close to hardware when needed \end{itemize} \end{block} From 42a18d0a3416cab3ce20f3ce054cda25019e3ecf Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Sun, 29 Sep 2024 15:16:43 +0200 Subject: [PATCH 101/156] Two micro-changes for the advanced part of core-modern. --- talk/morelanguage/exceptions.tex | 2 +- talk/morelanguage/templates.tex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/talk/morelanguage/exceptions.tex b/talk/morelanguage/exceptions.tex index e425efd8..df88885f 100644 --- a/talk/morelanguage/exceptions.tex +++ b/talk/morelanguage/exceptions.tex @@ -376,7 +376,7 @@ \item An exception will leave the program in a defined state \begin{itemize} \item At least destructors must be able to run - \item This is similar to the moved from state + \item This is similar to the moved-from state \end{itemize} \item No resources are leaked \end{itemize} diff --git a/talk/morelanguage/templates.tex b/talk/morelanguage/templates.tex index a8eca9c0..de87399e 100644 --- a/talk/morelanguage/templates.tex +++ b/talk/morelanguage/templates.tex @@ -479,7 +479,7 @@ std::array a{1, 2, 3}; // std::array std::mutex m; - std::lock_guard l(m); // std::lock_guard + std::lock_guard l{m}; // std::lock_guard \end{cppcode*} \end{block} \end{frame} From 6724c748f1244cbf41aeaa21fc87742906f336f8 Mon Sep 17 00:00:00 2001 From: David Chamont Date: Sun, 29 Sep 2024 18:48:51 +0200 Subject: [PATCH 102/156] Cosmetic --- exercises/optional/Makefile | 1 + exercises/optional/optional.cpp | 2 +- exercises/variant/solution/variant.sol1.cpp | 1 + exercises/variant/solution/variant.sol2.cpp | 1 + exercises/variant/variant.cpp | 3 ++- 5 files changed, 6 insertions(+), 2 deletions(-) diff --git a/exercises/optional/Makefile b/exercises/optional/Makefile index 1fa40ebd..feb7275d 100644 --- a/exercises/optional/Makefile +++ b/exercises/optional/Makefile @@ -1,3 +1,4 @@ + all: optional solution: optional.sol diff --git a/exercises/optional/optional.cpp b/exercises/optional/optional.cpp index ae815937..6ed57d1d 100644 --- a/exercises/optional/optional.cpp +++ b/exercises/optional/optional.cpp @@ -4,7 +4,7 @@ In the code below, modify the function `mysqrt` below so that it returns an `std::optional` rather than a double, and the program prints `nothing` rather than `nan` for the call with `-10`. It will also require -to modify `square`. +to update `square`. */ diff --git a/exercises/variant/solution/variant.sol1.cpp b/exercises/variant/solution/variant.sol1.cpp index f42c46c5..8e3f11c1 100644 --- a/exercises/variant/solution/variant.sol1.cpp +++ b/exercises/variant/solution/variant.sol1.cpp @@ -1,3 +1,4 @@ + #include #include #include diff --git a/exercises/variant/solution/variant.sol2.cpp b/exercises/variant/solution/variant.sol2.cpp index 79ba203c..4c48b64d 100644 --- a/exercises/variant/solution/variant.sol2.cpp +++ b/exercises/variant/solution/variant.sol2.cpp @@ -1,3 +1,4 @@ + #include #include #include diff --git a/exercises/variant/variant.cpp b/exercises/variant/variant.cpp index 2b626b0e..15b8502b 100644 --- a/exercises/variant/variant.cpp +++ b/exercises/variant/variant.cpp @@ -1,6 +1,7 @@ /* -In the code below, replace inheritance with the use of a std::variant. +In the code below, replace inheritance with the use of a `std::variant`. +There is no more need for a base class, and no more need pointers. Two solutions are provided : 1. with `std::get_if`, 2. with `std::visit`. From 550f705a6844b6640e737a99fcfe01ab5ddd0bd6 Mon Sep 17 00:00:00 2001 From: Daniele Massaro <66123362+Qubitol@users.noreply.github.com> Date: Mon, 30 Sep 2024 08:09:05 +0200 Subject: [PATCH 103/156] Fix typo extend -> extent in span section (#532) --- talk/morelanguage/morestl.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/talk/morelanguage/morestl.tex b/talk/morelanguage/morestl.tex index bb277474..c5cf8ce7 100644 --- a/talk/morelanguage/morestl.tex +++ b/talk/morelanguage/morestl.tex @@ -45,7 +45,7 @@ \begin{itemize} \item and thus to be passed by value \end{itemize} - \item \cppinline{span} can also have a \texttt{static extend} + \item \cppinline{span} can also have a \texttt{static extent} \begin{itemize} \item meaning the size is determined at compile time \item and thus only a pointer is stored by \cppinline{span} From 7e4c52b033a8d6830b8156290391853dd7f42c37 Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Mon, 30 Sep 2024 08:25:06 +0200 Subject: [PATCH 104/156] Add David as author as he now gived the course (#535) Co-authored-by: Sebastien Ponce --- talk/setup.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/talk/setup.tex b/talk/setup.tex index 2318b1a1..9f246154 100644 --- a/talk/setup.tex +++ b/talk/setup.tex @@ -405,7 +405,7 @@ %%%%%%%%%%%%%%%%%% \title{HEP \cpp course} -\author[B. Gruber, S. Hageboeck, S. Ponce]{B. Gruber, S. Hageboeck, S. Ponce \\ \texttt{sebastien.ponce@cern.ch}} +\author[D. Chamont, B. Gruber, S. Hageboeck, S. Ponce]{D.Chamont, B. Gruber, S. Hageboeck, S. Ponce \\ \texttt{sebastien.ponce@cern.ch}} \institute{CERN} \date{\today} \pgfdeclareimage[height=0.5cm]{cernlogo}{CERN-logo.jpg} From 8e7224bfc3ebff3d76f2eda2733fc542aa2bbd92 Mon Sep 17 00:00:00 2001 From: David Chamont Date: Sun, 29 Sep 2024 15:58:58 +0200 Subject: [PATCH 105/156] Splitting the smartPointers exercise into 5 problems. --- exercises/ExerciseSchedule_AdvancedCourse.md | 2 + exercises/code/memcheck/README.md | 0 exercises/smartPointers/CMakeLists.txt | 16 +- exercises/smartPointers/Makefile | 6 +- exercises/smartPointers/README.md | 23 +- exercises/smartPointers/problem1.cpp | 74 ++++ exercises/smartPointers/problem2.cpp | 90 +++++ exercises/smartPointers/problem3.cpp | 136 +++++++ exercises/smartPointers/problem4.cpp | 79 ++++ exercises/smartPointers/problem5.cpp | 113 ++++++ exercises/smartPointers/smartPointers.cpp | 337 ------------------ .../smartPointers/solution/problem1.sol.cpp | 44 +++ .../smartPointers/solution/problem2.sol.cpp | 61 ++++ .../smartPointers/solution/problem3.sol.cpp | 86 +++++ .../smartPointers/solution/problem4.sol.cpp | 43 +++ .../smartPointers/solution/problem5.sol.cpp | 83 +++++ .../solution/smartPointers.sol.cpp | 314 ---------------- 17 files changed, 837 insertions(+), 670 deletions(-) delete mode 100644 exercises/code/memcheck/README.md create mode 100644 exercises/smartPointers/problem1.cpp create mode 100644 exercises/smartPointers/problem2.cpp create mode 100644 exercises/smartPointers/problem3.cpp create mode 100644 exercises/smartPointers/problem4.cpp create mode 100644 exercises/smartPointers/problem5.cpp delete mode 100644 exercises/smartPointers/smartPointers.cpp create mode 100644 exercises/smartPointers/solution/problem1.sol.cpp create mode 100644 exercises/smartPointers/solution/problem2.sol.cpp create mode 100644 exercises/smartPointers/solution/problem3.sol.cpp create mode 100644 exercises/smartPointers/solution/problem4.sol.cpp create mode 100644 exercises/smartPointers/solution/problem5.sol.cpp delete mode 100644 exercises/smartPointers/solution/smartPointers.sol.cpp diff --git a/exercises/ExerciseSchedule_AdvancedCourse.md b/exercises/ExerciseSchedule_AdvancedCourse.md index 4c3da299..c6c55249 100644 --- a/exercises/ExerciseSchedule_AdvancedCourse.md +++ b/exercises/ExerciseSchedule_AdvancedCourse.md @@ -46,6 +46,8 @@ Day 3 ### Atomicity (directory: [`atomic`](atomic), [cheatSheet](ExercisesCheatSheet.md#atomicity-directory-atomic)) +### Condition variables (directory: [`condition_variable`](condition_variable), [cheatSheet](ExercisesCheatSheet.md#condition-variables-directory-condition_variable)) + ### Generic programming / templates (directory: [`templates`](templates), [cheatSheet](ExercisesCheatSheet.md#generic-programming--templates-directory-templates)) As a prerequisite for variadic templates, and in case it was not covered in day 2 session diff --git a/exercises/code/memcheck/README.md b/exercises/code/memcheck/README.md deleted file mode 100644 index e69de29b..00000000 diff --git a/exercises/smartPointers/CMakeLists.txt b/exercises/smartPointers/CMakeLists.txt index ed01281b..1d13482c 100644 --- a/exercises/smartPointers/CMakeLists.txt +++ b/exercises/smartPointers/CMakeLists.txt @@ -7,8 +7,16 @@ include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) set( CMAKE_CXX_STANDARD 20 ) # Create the user's executable. -add_executable( smartPointers "smartPointers.cpp" ) +add_executable( problem1 "problem1.cpp" ) +add_executable( problem2 "problem2.cpp" ) +add_executable( problem3 "problem3.cpp" ) +add_executable( problem4 "problem4.cpp" ) +add_executable( problem5 "problem5.cpp" ) -# Create the "solution executable". -add_executable( smartPointers.sol EXCLUDE_FROM_ALL "solution/smartPointers.sol.cpp" ) -add_dependencies( solution smartPointers.sol ) +# Create the "solution executables". +add_executable( problem1.sol EXCLUDE_FROM_ALL "solution/problem1.sol.cpp" ) +add_executable( problem2.sol EXCLUDE_FROM_ALL "solution/problem2.sol.cpp" ) +add_executable( problem3.sol EXCLUDE_FROM_ALL "solution/problem3.sol.cpp" ) +add_executable( problem4.sol EXCLUDE_FROM_ALL "solution/problem4.sol.cpp" ) +add_executable( problem5.sol EXCLUDE_FROM_ALL "solution/problem5.sol.cpp" ) +add_dependencies( solution problem1.sol problem2.sol problem3.sol problem4.sol problem5.sol ) diff --git a/exercises/smartPointers/Makefile b/exercises/smartPointers/Makefile index 9e8f8ad0..59041117 100644 --- a/exercises/smartPointers/Makefile +++ b/exercises/smartPointers/Makefile @@ -1,8 +1,8 @@ -all: smartPointers -solution: smartPointers.sol +all: problem1 problem2 problem3 problem4 problem5 +solution: problem1.sol problem2.sol problem3.sol problem4.sol problem5.sol clean: - rm -f *o *so smartPointers *~ smartPointers.sol + rm -f *o *so *~ problem? problem?.sol % : %.cpp $(CXX) -g -std=c++20 -Wall -Wextra -o $@ $< diff --git a/exercises/smartPointers/README.md b/exercises/smartPointers/README.md index 0cc9cd34..5c710bb9 100644 --- a/exercises/smartPointers/README.md +++ b/exercises/smartPointers/README.md @@ -1,25 +1,24 @@ -# Writing leak-free C++. -Here we have four code snippets that will benefit from using smart pointers. -By replacing every explicit `new` with `make_unique` or `make_shared`, -(alternatively by explicitly instantiating smart pointers) we will fix memory leaks, -and make most cleanup code unnecessary. +# Writing leak-free and fault-free C++ + +Here we have five code snippets that will benefit from using smart pointers. By replacing every explicit `new` with `make_unique` or `make_shared`, (alternatively by explicitly instantiating smart pointers) we will fix memory leaks, segmentation faults, and make most cleanup code unnecessary. ## Prerequisites -* Which pointer is used for what? +* Do you know which kind of pointer is used for what? * Raw pointer * [`std::unique_ptr`](https://en.cppreference.com/w/cpp/memory/unique_ptr) * [`std::shared_ptr`](https://en.cppreference.com/w/cpp/memory/shared_ptr) * C++-14 for `std::make_unique` / `std::make_shared`. Understand what these functions do. -* Helpful: Move semantics for `problem2()`, but can do without. +* Helpful: Move semantics for `problem2()`, but one can do without. ## Instructions -* Compile and run the program. It doesn't generate any output. -* Run with valgrind to check for leaks +* In the **essentials course**, work on `problem1` and `problem2`, and fix the leaks using smart pointers. +* In the **advanced course**, work on `problem1` to `problem5`. Skip `problem4` and `problem5` if you don't have enough time. +* Dedicated instructions are given in each cpp file. +* Each one is written so that you easily check if the problem is solved or not. +* If seen in course before, you are also advised to try external tools such as valgrind: ``` -valgrind --leak-check=full --track-origins=yes ./smartPointers +valgrind --leak-check=full --track-origins=yes ./problem1 ``` -* In the **essentials course**, work on `problem1()` and `problem2()`, and fix the leaks using smart pointers. -* In the **advanced course**, work on `problem1()` to `problem4()`. Skip `problem4()` if you don't have enough time. diff --git a/exercises/smartPointers/problem1.cpp b/exercises/smartPointers/problem1.cpp new file mode 100644 index 00000000..4524c0ee --- /dev/null +++ b/exercises/smartPointers/problem1.cpp @@ -0,0 +1,74 @@ + + +#include +#include + + +/* -------------------------------------------------------------------------------------------- + * Unique ownership. + * + * Always use smart pointers instead of `new`. A frequent source of memory leaks is a function + * that terminates in an unexpected way. + * + * Tasks + * 1) Compile and run the code below. Notice that the final count is `1`, + * showing that the instance of LargeObject has not been deallocated. + * 2) Modify `doStuff()` (only) so to use a `std::unique_ptr` instead of a raw pointer. + * The final count should be `0`, and the memory leak solved. + * -------------------------------------------------------------------------------------------- + */ + + +// The class LargeObject emulates a large object. +// One should avoid to copy it, and rather use +// a pointer to pass it around. + +struct LargeObject { + + std::array data ; + + // So to check for some potential memory leak, + // we count the constructions and destructions + static std::size_t count ; + LargeObject() { count++ ; } + ~LargeObject() { count-- ; } + +} ; + +std::size_t LargeObject::count = 0 ; + +// A function to do something with a large object. +// Here we simulate that an error happens. + +void changeLargeObject( LargeObject & object ) { + + object.data[0] = 1. ; + throw std::invalid_argument("Error when changing object data.") ; + +} + +// Often, data are owned by one entity, and merely used by others. +// In this case, we hand the data to changeLargeObject(), +// and unfortunately, something goes wrong... + +void doStuff() { + + // MAKE YOUR CHANGES IN THIS FUNCTION + + auto obj = new LargeObject ; + changeLargeObject(*obj) ; + delete obj ; + +} + +int main() { + + try { + doStuff() ; + } catch ( const std::exception & e ) { + std::cerr<< "Terminated with exception: " << e.what() << "\n" ; + } + + std::cout<<"Forgotten large objects: "< +#include +#include + + +/* -------------------------------------------------------------------------------------------- + * Collections of smart pointers. + * + * Often, one has to store pointers to objects in collections. + * Fix the memory leaks below by using `std::unique_ptr`. + * + * Tasks + * 1) Compile and run the code below. Notice that the final count is `10`, + * which is expected because the new objects are never deallocated. + * 2) Factory functions should better return smart pointers, + * because it clarifies who owns an object. + * Change the return type of the function `newLargeObject()` for a `std::unique_ptr()`. + * The vector should own the objects, so try to store them using smart pointers. + * Since the change function doesn't accept smart pointers, find a solution to pass the objects. + * Try to use `std::unique_ptr`, not `std::shared_ptr` ! + * -------------------------------------------------------------------------------------------- + */ + + +// The class LargeObject emulates a large object. +// One should avoid to copy it, and rather use +// a pointer to pass it around. + +struct LargeObject { + + std::array data ; + + // So to check for some potential memory leak, + // we count the constructions and destructions + static std::size_t count ; + LargeObject() { count++ ; } + ~LargeObject() { count-- ; } + +} ; + +std::size_t LargeObject::count = 0 ; + +// A factory function to create large objects. + +LargeObject * newLargeObject() { + + // MAKE YOUR CHANGES IN THIS FUNCTION + + auto object = new LargeObject() ; + // Imagine there is more setup steps of "object" here + // ... + return object ; + +} + +// A function to do something with the objects. +// Note that since we don't own the object, +// we don't need a smart pointer as argument. + +void changeLargeObject( LargeObject & object ) { + + object.data[0] = 1. ; + +} + +void doStuff() { + + // MAKE YOUR CHANGES IN THIS FUNCTION + + std::vector largeObjects ; + + for ( unsigned int i = 0 ; i < 10 ; ++i ) { + auto newObj = newLargeObject() ; + // ... additional newObj setup ... + largeObjects.push_back(newObj) ; + } + + for ( const auto & obj : largeObjects ) { + changeLargeObject(*obj) ; + } +} + +int main() { + + doStuff() ; + std::cout<<"Forgotten large objects: "< +#include +#include +#include +#include + + +/* -------------------------------------------------------------------------------------------- + * Shared ownership. + * + * Most of the time, ownership can be solved by having one owner (with `std::unique_ptr`) and + * one or more observers (raw pointers or references). Sometimes, we need to truly share data, + * though. Here is an example of a completely messed up ownership model. + * + * Tasks + * 1) Verify the mess by repeatedly running it using such a command like: + * `while true; do ./problem3 2>&1 ; done` + * You should notice that the program regularly leaks. + * 2) Fix the ownership model using `std::shared_ptr` ! + * - Convert the vectors to holding `std::shared_ptr`. + * - Fix the arguments of the functions. + * 3) Speed optimisation: make sure that you don't create & destroy useless `std::shared_ptr`, + * which is slow, for example in the for loop of `doStuff()` and when + * calling `changeLargeObject()`. + * -------------------------------------------------------------------------------------------- + */ + + +// The class LargeObject emulates a large object. +// One should avoid to copy it, and rather use +// a pointer to pass it around. + +struct LargeObject { + + std::array data ; + + // So to check for some potential memory leak, + // we count the constructions and destructions + static std::size_t count ; + LargeObject() { count++ ; } + ~LargeObject() { count-- ; } + +} ; + +std::size_t LargeObject::count = 0 ; + +// This removes an element from a non-owning vector, +// in the middle or in a random place. Such elements +// can by known in several vectors, so they must not +// be deleted. + +void removeMiddle( std::vector & collection ) { + + // MAKE YOUR CHANGES IN THIS FUNCTION + + auto middlePosition = collection.begin() + collection.size()/2 ; + collection.erase(middlePosition) ; + +} + +void removeRandom( std::vector & collection, std::default_random_engine & engine ) { + + // MAKE YOUR CHANGES IN THIS FUNCTION + + auto pos = collection.begin() + engine() % collection.size() ; + collection.erase(pos); + +} + +// A function to do something with a large object. +// Note that since we don't own the object, +// we don't need a smart pointer as argument. + +void changeLargeObject( LargeObject & object ) { + + object.data[0] = 1. ; + +} + +// Global stuff: we have pointers to objects duplicated in two different collections. +// We work a bit with the collections, and then we try to clean up without neither +// memory leak nor segmentation fault. Without a shared ownership model, this becomes a mess. + +void doStuff() { + + // MAKE YOUR CHANGES IN THIS FUNCTION + + // Prepare a non deterministic random engine + + std::random_device device ; + std::default_random_engine engine(device()) ; + + // Original collection + + std::vector objVector(10); + for ( auto & ptr : objVector ) { + ptr = new LargeObject(); + } + + // Let's copy the whole collection + + auto objVectorCopy(objVector); + + // Random work with the objects + + removeMiddle(objVector); + removeRandom(objVectorCopy,engine); + removeRandom(objVectorCopy,engine); + // ... + for (auto objPtr : objVector ) { + changeLargeObject(*objPtr) ; + } + + // ONCE YOU FIXED CODE ABOVE WITH SHARED POINTERS + // THE UGLY CODE BELOW SHOULD BECOME UNNECESSARY + + for ( auto objPtr : objVector ) { + delete objPtr ; + } + for ( auto objPtr : objVectorCopy ) { + // If the element is in the original collection, it was already deleted. + if (std::find(objVector.begin(), objVector.end(), objPtr) == objVector.end()) { + delete objPtr; + } + } + +} + +int main() { + + doStuff() ; + std::cout<<"Forgotten large objects: "< +#include +#include + + +/* -------------------------------------------------------------------------------------------- + * Smart pointers as class members. + * + * Class members that are pointers can quickly become a problem. + * Firstly, if only raw pointers are used, the intended ownership is unclear. + * Secondly, it's easy to overlook that a member has to be deleted. + * Thirdly, pointer members usually require you to implement copy or move constructors + * and assignment operators (--> rule of 3, rule of 5). + * Since C++-11, one can solve a few of those problems using smart pointers. + * + * The class "Owner" owns some data, but it is broken. If you copy it like in + * doStuff(), you have two pointers pointing to the same data, but both instances + * think that they own the data. + * + * Tasks + * 1) It likely crashes. Verify this. You can also try running `valgrind ./problem4`, + * it should give you some hints as to what's happening. + * 2) Fix the Owner class by using a `std::shared_ptr` for its data, which we can + * copy as much as we want. Run the fixed program. + * Note: Once `std::shared_ptr` is in use, you can also use the default destructor. + * + * -------------------------------------------------------------------------------------------- + */ + +struct LargeObject { + + std::array data ; + +} ; + +class Owner { + + // MAKE YOUR CHANGES IN THIS CLASS + + public: + + Owner() : _largeObject( new LargeObject() ) {} + LargeObject * getLargeObject() { return _largeObject ; } + ~Owner() { delete _largeObject ; } + + private: + + LargeObject * _largeObject ; + +} ; + +void doStuff() { + + std::vector owners ; + + for ( int i = 0 ; i < 5 ; ++i ) { + Owner owner ; + // ... additional owner setup ... + owners.push_back(owner) ; + } + + /* Now we have a problem: + * We created Owner instances on the stack, and copied them into the vector. + * When the instances on the stack are destroyed, the memory is deallocated. + * All copies in the vector now point to the deallocated memory! + * We could fix this using copy constructors (but we don't want to copy the data), + * using move semantics or using shared_ptr. + * Here, we want to go for shared_ptr. + */ + +} + +int main() { + + doStuff() ; + +} diff --git a/exercises/smartPointers/problem5.cpp b/exercises/smartPointers/problem5.cpp new file mode 100644 index 00000000..8a6f9ea4 --- /dev/null +++ b/exercises/smartPointers/problem5.cpp @@ -0,0 +1,113 @@ + + +#include +#include +#include +#include + + +/* -------------------------------------------------------------------------------------------- + * Weak pointers. + * + * Let's construct some `std::weak_ptr` so to observe some `std::shared_ptr`. + * This weak pointers can be used to retreive the object pointed by the corresponding `std::shared_ptr`, + * but it does not increase the reference count of the objects, and does not prevent + * the deletion of the underlying objects if all shared pointers go out of scope. + * To *use* the observed data, one has to create a `std::shared_ptr` from the `std::weak_ptr`, + * so that it is guaranteed that the underlying object is alive. + * + * In our case, the `Observer` class wants to act on the data of the `Owner`, + * but it doesn't need to own it. To do this, we use a weak pointer. + * + * Tasks + * 1) Investigate the crash. Optionally use a debugger, run in valgrind, + * compile with -fsanitize=address ... + * 2) Rewrite the interface of Owner::getData() such that the observer can see the + * `std::shared_ptr` pointing to the large object. + * Review the class `Observer` such that it stores a `std::weak pointer`. + * In `setValue`and `getValue`, access the weak pointer, and use the data *only* if the memory is still alive. + * Note: What you need is weak_ptr::lock(). Check out the documentation and the example at the bottom: + * https://en.cppreference.com/w/cpp/memory/weak_ptr/lock + * + * -------------------------------------------------------------------------------------------- + */ + +struct LargeObject { + + std::array data ; + +} ; + +class Owner { + + // SOME CHANGES NEEDED IN THIS CLASS + + public: + + Owner() : _largeObject( new LargeObject() ) {} + LargeObject * getLargeObject() const { return _largeObject.get() ; } + + private: + + std::shared_ptr _largeObject ; + +} ; + +class Observer { + + // SOME CHANGES NEEDED IN THIS CLASS + + public: + + Observer( const Owner & owner ) : _largeObject(owner.getLargeObject()) {} + + void setValue( double v ) { + if (_largeObject) { _largeObject->data[0] = v ; } + else { _largeObject->data[0] = 0. ; } + } + + double getValue() const { + if (_largeObject) { return _largeObject->data[0] ; } + else { return -1. ; } + } + + private: + + LargeObject * _largeObject ; + +} ; + +void doStuff() { + + // Owners and observers + + std::vector owners(5) ; + std::vector observers ; + for ( auto & owner : owners ) { + observers.emplace_back(owner) ; + } + + // Write through observers + + for ( auto & observer : observers ) { + observer.setValue(1.) ; + } + + // Let's destroy the 2 last owners + + owners.resize(3) ; + + // Read through observers + + std::cout << "Values:"; + for ( auto const & observer : observers ) { + std::cout<<" "< -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* - * Please fix all memory leaks / ownership problems using smart pointers. - * (Verify by running the program with valgrind!) - * - * In the *essentials course*: - * - Work on problem1() and problem2() - * - You can have a look at problem3() if interested - * - * In the *advanced course*: - * - Work on problem1() to problem4() - * - * In main() at the bottom, comment in the different parts as you progress through the exercise. - * - * Remember that: - * - The unique ownership of data is expressed using unique_ptr. - * - "Observer" access without ownership is expressed using raw pointers, references or spans. - * - Shared ownership to data is expressed using shared_ptr. - */ - - -/* -------------------------------------------------------------------------------------------- - * 1: Always use smart pointers instead of new. - * - * A frequent source of leaks is a function that terminates in an unexpected way. - * - * - Fix the leak using a smart pointer. - * - The arguments of sumEntries() don't need to change, as it has only read access. - * -------------------------------------------------------------------------------------------- - */ - -// Note how we are using a span pointing to "double const" to ensure that the -// data can only be read. You don't need to change anything in this function. -double sumEntries(std::span range) { - // Simulate an error - throw std::invalid_argument("Error when summing over data."); - - return std::reduce(range.begin(), range.end()); -} - -// Often, data are owned by one entity, and merely used by others. In this case, we hand the data to -// sumEntries() for reading, so the ownership stays with this function. Unfortunately, something goes -// wrong and we didn't use smart pointers. -// Understand and fix the memory leak. -void doStuffWithData() { - auto data = new std::array{}; - - sumEntries(*data); - - delete data; -} - - -void problem1() { - try { - doStuffWithData(); - } catch (const std::exception& e) { - std::cerr << "problem1() terminated with exception: \"" << e.what() - << "\" Check for memory leaks.\n"; - } -} - - - -/* -------------------------------------------------------------------------------------------- - * 2: Storing unique_ptr in collections. - * - * Often, one has to store pointers to objects in collections. Fix the memory leaks using unique_ptr. - * - * Notes: - * - Factory functions should return objects either directly or using smart pointers. - * This is good practice, because it clearly shows who owns an object. Fix the return type of the factory function. - * - The vector should own the objects, so try to store them using smart pointers. - * - Since the change function doesn't accept smart pointers, find a solution to pass the objects. - * Note that this works without shared_ptr! - * -------------------------------------------------------------------------------------------- - */ - -// This is a large object. We maybe shouldn't copy it, so using a pointer is advisable to pass it around. -struct LargeObject { - std::array fData; -}; - -// A factory function to create large objects. -LargeObject* createLargeObject() { - auto object = new LargeObject(); - // Imagine there is more setup steps of "object" here - // ... - - return object; -} - -// A function to do something with the objects. -// Note that since we don't own the object, we don't need a smart pointer as argument. -void changeLargeObject(LargeObject& object) { - object.fData[0] = 1.; -} - -void problem2() { - std::vector largeObjects; - - for (unsigned int i=0; i < 10; ++i) { - auto newObj = createLargeObject(); - largeObjects.push_back(newObj); - } - - for (const auto& obj : largeObjects) { - changeLargeObject(*obj); - } -} - - - -/* -------------------------------------------------------------------------------------------- - * 3: Shared ownership. - * - * Most of the time, ownership can be solved by having one owner (with unique_ptr) and one or - * more observers (raw pointers or references). Sometimes, we need to truly share data, though. - * - * Here is an example of a completely messed up ownership model. It leaks about 1/10 of the times - * it is invoked. - * - Verify this by running it in a loop using a command like: - * while true; do valgrind --leak-check=full --track-origins=yes ./smartPointers 2>&1 | grep -B 5 -A 5 problem3 && exit 1; done - * - Fix the ownership model using shared_ptr! - * - Convert the vectors to holding shared_ptr. - * - Fix the arguments of the functions. - * - Speed optimisation: - * Make sure that you don't create & destroy a shared_ptr in the for loop in problem3() and when calling processElement(). - * -------------------------------------------------------------------------------------------- - */ - -// This removes the element in the middle of the vector. -void removeMiddle(std::vector& collection) { - auto middlePosition = collection.begin() + collection.size()/2; - - // Must not delete element when erasing from collection, because it's also in the copy ... - collection.erase(middlePosition); -} - -// This removes a random element. -// Note that this leaks if the element happens to be the same -// that's removed above ... -void removeRandom(std::vector& collection) { - auto pos = collection.begin() + time(nullptr) % collection.size(); - - collection.erase(pos); -} - -// Do something with an element. -// Just a dummy function, for you to figure out how to pass an object -// managed by a shared_ptr to a function. -void processElement(const LargeObject* /*element*/) { } - - -// We have pointers to objects in two different collections. We work a bit with -// the collections, and then we try to terminate leak free. Without a shared ownership -// model, this becomes a mess. -void problem3() { - // Let's generate a vector with 10 pointers to LargeObject - std::vector objVector(10); - for (auto& ptr : objVector) { - ptr = new LargeObject(); - } - - // Let's copy it - std::vector objVectorCopy(objVector); - - - // Now we work with the objects: - removeMiddle(objVector); - removeRandom(objVectorCopy); - // ... - // ... - for (auto elm : objVector) { - processElement(elm); - } - - - // Now try to figure out what has to be deleted. It's a mess ... - // Fix using shared_ptr, so the following code becomes unnecessary: - for (auto objPtr : objVector) { - delete objPtr; - } - - for (auto objPtr : objVectorCopy) { - // If the element is in the original collection, it was already deleted. - if (std::find(objVector.begin(), objVector.end(), objPtr) == objVector.end()) { - delete objPtr; - } - } -} - - - -/* -------------------------------------------------------------------------------------------- - * 4: Smart pointers as class members. - * - * Class members that are pointers can quickly become a problem. - * Firstly, if only raw pointers are used, the intended ownership is unclear. - * Secondly, it's easy to overlook that a member has to be deleted. - * Thirdly, pointer members usually require you to implement copy or move constructors and assignment - * operators (--> rule of 3, rule of 5). - * Since C++-11, one can solve a few of those problems using smart pointers. - * - * 4.1: - * The class "Owner" owns some data, but it is broken. If you copy it like in - * problem4_1(), you have two pointers pointing to the same data, but both instances think - * that they own the data. - * - * Tasks: - * - Comment in problem4_1() in main(). - * - It likely crashes. Verify this. You can also try running valgrind ./smartPointers, it should give you some hints as to - * what's happening. - * - Fix the Owner class by using a shared_ptr for its _largeObj, which we can copy as much as we want. - * - Run the fixed program. - * - Note: Once shared_ptr is in use, you can also use the default destructor. - * - * 4.2: **BONUS** - * Let's use a weak_ptr now to observe a shared_ptr. - * These are used to observe a shared_ptr, but unlike the shared_ptr, they don't prevent the deletion - * of the underlying object if all shared_ptr go out of scope. - * To *use* the observed data, one has to create a shared_ptr from the weak_ptr, so that it is guaranteed that - * the underlying object is alive. - * - * In our case, the observer class wants to observe the data of the owner, but it doesn't need to own it. - * To do this, we use a weak pointer. - * - * Tasks: - * - Comment in problem4_2() in main(). - * - Investigate the crash. Use a debugger, run in valgrind, compile with -fsanitize=address ... - * - Rewrite the interface of Owner::getData() such that the observer can see the shared_ptr to the large object. - * - Set up the Observer such that it stores a weak pointer that observes the large object. - * - In Observer::processData(), access the weak pointer, and use the data *only* if the memory is still alive. - * Note: What you need is weak_ptr::lock(). Check out the documentation and the example at the bottom: - * https://en.cppreference.com/w/cpp/memory/weak_ptr/lock - * -------------------------------------------------------------------------------------------- - */ - -class Owner { -public: - Owner() : - _largeObj(new LargeObject()) { } - - ~Owner() { - std::cout << "problem4(): Owner " << this << " is deallocating " << _largeObj << ".\n"; - delete _largeObj; - } - - const LargeObject* getData() const { - return _largeObj; - } - -private: - LargeObject* _largeObj; -}; - - -void problem4_1() { - std::vector owners; - - for (int i=0; i < 5; ++i) { - Owner owner; - owners.push_back(owner); - } - - /* Now we have a problem: - * We created Owner instances on the stack, and copied them into the vector. - * When the instances on the stack are destroyed, the memory is deallocated. - * All copies in the vector now point to the deallocated memory! - * We could fix this using copy constructors (but we don't want to copy the data), - * using move semantics or using shared_ptr. - * Here, we want to go for shared_ptr. - */ -} - - -class Observer { -public: - Observer(const Owner& owner) : - _largeObj(owner.getData()) { } - - double getValue() const { - if (_largeObj) { - return _largeObj->fData[0]; - } - - return -1.; - } - -private: - const LargeObject* _largeObj; // We don't own this. -}; - - - -void problem4_2() { - // We directly construct 5 owners inside the vector to get around problem4_1: - std::vector owners(5); - - // Let's now fill the other vector with observers: - std::vector observers; - observers.reserve(owners.size()); - for (const auto& owner : owners) { - observers.emplace_back(owner); - } - - // Now let's destroy a few of the data owners: - owners.resize(3); - - std::cout << "Values of the observers:\n\t"; - for (const auto& observer : observers) { - // Problem: We don't know if the data is alive ... - // TODO: Fix Observer! - // std::cout << observer.getValue() << " "; - } - std::cout << "\n"; -} - - -int main() { - problem1(); - // problem2(); - // problem3(); - // problem4_1(); - // problem4_2(); -} diff --git a/exercises/smartPointers/solution/problem1.sol.cpp b/exercises/smartPointers/solution/problem1.sol.cpp new file mode 100644 index 00000000..a6c4e3fa --- /dev/null +++ b/exercises/smartPointers/solution/problem1.sol.cpp @@ -0,0 +1,44 @@ + +#include +#include +#include + +struct LargeObject { + + std::array data ; + + // So to check for some potential memory leak, + // we count the constructions and destructions + static std::size_t count ; + LargeObject() { count++ ; } + ~LargeObject() { count-- ; } + +} ; + +std::size_t LargeObject::count = 0 ; + +void changeLargeObject( LargeObject & object ) { + + object.data[0] = 1. ; + throw std::invalid_argument("Error when changing object data.") ; + +} + +void doStuff() { + + auto obj = std::make_unique() ; + changeLargeObject(*obj) ; + +} + +int main() { + + try { + doStuff() ; + } catch ( const std::exception & e ) { + std::cerr<< "Terminated with exception: " << e.what() << "\n" ; + } + + std::cout<<"Forgotten large objects: "< +#include +#include +#include + + +struct LargeObject { + + std::array data ; + + // So to check for some potential memory leak, + // we count the constructions and destructions + static std::size_t count ; + LargeObject() { count++ ; } + ~LargeObject() { count-- ; } + +} ; + +std::size_t LargeObject::count = 0 ; + +std::unique_ptr newLargeObject() { + + auto object = std::make_unique() ; + // Imagine there is more setup steps of "object" here + // ... + return object ; +} + +void changeLargeObject( LargeObject & object ) { + + object.data[0] = 1. ; + +} + +void doStuff() { + + std::vector> largeObjects ; + + for ( unsigned int i = 0 ; i < 10 ; ++i ) { + largeObjects.push_back(newLargeObject()); + // ... additional largeObjects.back() setup ... + + // Alternatively, when the object is ready, + // one can "give up" newObj + // by moving it into the vector. + // auto newObj = createLargeObject() ; + // ... additional newObj setup ... + // largeObjects.push_back(std::move(newObj)); + + } + + for (const auto& obj : largeObjects) { + changeLargeObject(*obj); + } +} + +int main() { + doStuff() ; + std::cout<<"Forgotten large objects: "< +#include +#include +#include +#include +#include + +struct LargeObject { + + std::array data ; + + // So to check for some potential memory leak, + // we count the constructions and destructions + static std::size_t count ; + LargeObject() { count++ ; } + ~LargeObject() { count-- ; } + +} ; + +std::size_t LargeObject::count = 0 ; + +void removeMiddle(std::vector>& collection) { + + auto middlePosition = collection.begin() + collection.size()/2; + collection.erase(middlePosition); + +} + +void removeRandom(std::vector>& collection, std::default_random_engine & engine) { + + auto pos = collection.begin() + engine() % collection.size(); + collection.erase(pos); + +} + +void changeLargeObject( LargeObject & object ) { + + object.data[0] = 1. ; + +} + +void doStuff() { + + // Prepare a non deterministic random engine + + std::random_device device ; + std::default_random_engine engine(device()) ; + + // Original collection + + std::vector> objVector(10); + for ( auto & ptr : objVector ) { + ptr = std::make_shared(); + } + + // Less copies : + // std::vector> objVector ; + // objVector.reserve(10); + // for ( unsigned int i = 0 ; i < 10 ; ++i ) { + // objVector.emplace_back(new LargeObject()) ; + // } + + // Let's copy the whole collection + + auto objVectorCopy(objVector); + + // Random work with the objects + + removeMiddle(objVector); + removeRandom(objVectorCopy,engine); + removeRandom(objVectorCopy,engine); + // ... + // ... + for ( auto const & objPtr : objVector ) { + changeLargeObject(*objPtr) ; + } + +} + +int main() { + + doStuff() ; + std::cout<<"Forgotten large objects: "< +#include +#include +#include + + +struct LargeObject { + + std::array data ; + +} ; + +class Owner { + + public: + + Owner() : _largeObject( new LargeObject() ) {} + LargeObject * getLargeObject() const { return _largeObject.get() ; } + + private: + + std::shared_ptr _largeObject ; + +} ; + +void doStuff() { + + std::vector owners ; + + for ( int i = 0 ; i < 5 ; ++i ) { + Owner owner ; + // ... additional owner setup ... + owners.push_back(owner) ; + } +} + +int main() { + + doStuff() ; + +} diff --git a/exercises/smartPointers/solution/problem5.sol.cpp b/exercises/smartPointers/solution/problem5.sol.cpp new file mode 100644 index 00000000..154af2fc --- /dev/null +++ b/exercises/smartPointers/solution/problem5.sol.cpp @@ -0,0 +1,83 @@ + +#include +#include +#include +#include + +struct LargeObject { + + std::array data ; + +} ; + +class Owner { + + public: + + Owner() : _largeObject( new LargeObject() ) {} + auto getLargeObject() const { return _largeObject ; } + + private: + + std::shared_ptr _largeObject ; + +} ; + +class Observer { + + public: + + Observer( const Owner & owner ) : _largeObject(owner.getLargeObject()) {} + + void setValue( double v ) { + std::shared_ptr wptr = _largeObject.lock(); + if (wptr) { wptr->data[0] = v ; } + else { wptr->data[0] = 0. ; } + } + + double getValue() const { + std::shared_ptr wptr = _largeObject.lock(); + if (wptr) { return wptr->data[0] ; } + else { return -1. ; } + } + + private: + + std::weak_ptr _largeObject ; + +} ; + +void doStuff() { + + // Owners and observers + + std::vector owners(5) ; + std::vector observers ; + for ( auto & owner : owners ) { + observers.emplace_back(owner) ; + } + + // Write through observers + + for ( auto & observer : observers ) { + observer.setValue(1.) ; + } + + // Let's destroy the 2 last owners + + owners.resize(3) ; + + // Read through observers + + std::cout << "Values:"; + for ( auto const & observer : observers ) { + std::cout<<" "< -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* - * Please fix all memory leaks / ownership problems using smart pointers. - * (Verify by running the program with valgrind!) - * - * In the *essentials course*: - * - Work on problem1() and problem2() - * - You can have a look at problem3() if interested - * - * In the *advanced course*: - * - Work on problem1() to problem4() - * - * In main() at the bottom, comment in the different parts as you progress through the exercise. - * - * Remember that: - * - The unique ownership of data is expressed using unique_ptr. - * - "Observer" access without ownership is expressed using raw pointers, references or spans. - * - Shared ownership to data is expressed using shared_ptr. - */ - - -/* -------------------------------------------------------------------------------------------- - * 1: Always use smart pointers instead of new. - * - * A frequent source of leaks is a function that terminates in an unexpected way. - * - * - Fix the leak using a smart pointer. - * - The arguments of sumEntries() don't need to change, as it has only read access. - * -------------------------------------------------------------------------------------------- - */ - -// Note how we are using a span pointing to "double const" to ensure that the -// data can only be read. You don't need to change anything in this function. -double sumEntries(std::span range) { - // Simulate an error - throw std::invalid_argument("Error when summing over data."); - - return std::reduce(range.begin(), range.end()); -} - -// Often, data are owned by one entity, and merely used by others. In this case, we hand the data to -// sumEntries() for reading, so the ownership stays with this function. Unfortunately, something goes -// wrong and we didn't use smart pointers. -// Understand and fix the memory leak. -void doStuffWithData() { - auto data = std::make_unique>(); - - sumEntries(*data); -} - - -void problem1() { - try { - doStuffWithData(); - } catch (const std::exception& e) { - std::cerr << "problem1() terminated with exception: \"" << e.what() - << "\" Check for memory leaks.\n"; - } -} - - - -/* -------------------------------------------------------------------------------------------- - * 2: Storing unique_ptr in collections. - * - * Often, one has to store pointers to objects in collections. Fix the memory leaks using unique_ptr. - * - * Notes: - * - Factory functions should return objects either directly or using smart pointers. - * This is good practice, because it clearly shows who owns an object. Fix the return type of the factory function. - * - The vector should own the objects, so try to store them using smart pointers. - * - Since the change function doesn't accept smart pointers, find a solution to pass the objects. - * Note that this works without shared_ptr! - * -------------------------------------------------------------------------------------------- - */ - -// This is a large object. We maybe shouldn't copy it, so using a pointer is advisable to pass it around. -struct LargeObject { - std::array fData; -}; - -// A factory function to create large objects. -std::unique_ptr createLargeObject() { - auto object = std::make_unique(); - // Imagine there is more setup steps of "object" here - // ... - - return object; -} - -// A function to do something with the objects. -// Note that since we don't own the object, we don't need a smart pointer as argument. -void changeLargeObject(LargeObject& object) { - object.fData[0] = 1.; -} - -void problem2() { - std::vector> largeObjects; - - for (unsigned int i=0; i < 10; ++i) { - auto newObj = createLargeObject(); - largeObjects.push_back(std::move(newObj)); // Can only have one copy, so need to "give up" newObj by moving it into the vector. - - // Alternatively: - // largeObject.push_back(createLargeObject()); - } - - for (const auto& obj : largeObjects) { - changeLargeObject(*obj); - } -} - - - -/* -------------------------------------------------------------------------------------------- - * 3: Shared ownership. - * - * Most of the time, ownership can be solved by having one owner (with unique_ptr) and one or - * more observers (raw pointers or references). Sometimes, we need to truly share data, though. - * - * Here is an example of a completely messed up ownership model. It leaks about 1/10 of the times - * it is invoked. - * - Verify this by running it in a loop using a command like: - * while true; do valgrind --leak-check=full --track-origins=yes ./smartPointers 2>&1 | grep -B 5 -A 5 problem3 && exit 1; done - * - Fix the ownership model using shared_ptr! - * - Convert the vectors to holding shared_ptr. - * - Fix the arguments of the functions. - * - Speed optimisation: - * Make sure that you don't create & destroy a shared_ptr in the for loop in problem3() and when calling processElement(). - * -------------------------------------------------------------------------------------------- - */ - -// This removes the element in the middle of the vector. -void removeMiddle(std::vector>& collection) { - auto middlePosition = collection.begin() + collection.size()/2; - - // Must not delete element when erasing from collection, because it's also in the copy ... - collection.erase(middlePosition); -} - -// This removes a random element. -// Note that this leaks if the element happens to be the same -// that's removed above ... -void removeRandom(std::vector>& collection) { - auto pos = collection.begin() + time(nullptr) % collection.size(); - - collection.erase(pos); -} - -// Do something with an element. -// Just a dummy function, for you to figure out how to pass an object -// managed by a shared_ptr to a function. -void processElement(const LargeObject* /*element*/) { } - - -// We have pointers to objects in two different collections. We work a bit with -// the collections, and then we try to terminate leak free. Without a shared ownership -// model, this becomes a mess. -void problem3() { - // Let's generate a vector with 10 pointers to LargeObject - std::vector> objVector; - objVector.reserve(10); - for (unsigned int i = 0; i < 10; i++) { - objVector.emplace_back(new LargeObject()); - } - - // Let's copy it - std::vector> objVectorCopy(objVector); - - - // Now we work with the objects: - removeMiddle(objVector); - removeRandom(objVectorCopy); - // ... - // ... - for (const auto& elm : objVector) { - processElement(elm.get()); - } - - // Destruction happens automatically! -} - - - -/* -------------------------------------------------------------------------------------------- - * 4: Smart pointers as class members. - * - * Class members that are pointers can quickly become a problem. - * Firstly, if only raw pointers are used, the intended ownership is unclear. - * Secondly, it's easy to overlook that a member has to be deleted. - * Thirdly, pointer members usually require you to implement copy or move constructors and assignment - * operators (--> rule of 3, rule of 5). - * Since C++-11, one can solve a few of those problems using smart pointers. - * - * 4.1: - * The class "Owner" owns some data, but it is broken. If you copy it like in - * problem4_1(), you have two pointers pointing to the same data, but both instances think - * that they own the data. - * - * Tasks: - * - Comment in problem4_1() in main(). - * - It likely crashes. Verify this. You can also try running valgrind ./smartPointers, it should give you some hints as to - * what's happening. - * - Fix the Owner class by using a shared_ptr for its _largeObj, which we can copy as much as we want. - * - Run the fixed program. - * - Note: Once shared_ptr is in use, you can also use the default destructor. - * - * 4.2: **BONUS** - * Let's use a weak_ptr now to observe a shared_ptr. - * These are used to observe a shared_ptr, but unlike the shared_ptr, they don't prevent the deletion - * of the underlying object if all shared_ptr go out of scope. - * To *use* the observed data, one has to create a shared_ptr from the weak_ptr, so that it is guaranteed that - * the underlying object is alive. - * - * In our case, the observer class wants to observe the data of the owner, but it doesn't need to own it. - * To do this, we use a weak pointer. - * - * Tasks: - * - Comment in problem4_2() in main(). - * - Investigate the crash. Use a debugger, run in valgrind, compile with -fsanitize=address ... - * - Rewrite the interface of Owner::getData() such that the observer can see the shared_ptr to the large object. - * - Set up the Observer such that it stores a weak pointer that observes the large object. - * - In Observer::processData(), access the weak pointer, and use the data *only* if the memory is still alive. - * Note: What you need is weak_ptr::lock(). Check out the documentation and the example at the bottom: - * https://en.cppreference.com/w/cpp/memory/weak_ptr/lock - * -------------------------------------------------------------------------------------------- - */ - -class Owner { -public: - Owner() : - _largeObj(new LargeObject()) { } - - std::shared_ptr getData() const { - return _largeObj; - } - -private: - std::shared_ptr _largeObj; -}; - - -void problem4_1() { - std::vector owners; - - for (int i=0; i < 5; ++i) { - Owner owner; - owners.push_back(owner); - } - - // No problem now. Every object is deallocated only once. -} - - -class Observer { -public: - Observer(const Owner& owner) : - _largeObj(owner.getData()) { } - - double getValue() const { - if (auto data = _largeObj.lock()) { - return data->fData[0]; - } - - return -1.; - } - -private: - std::weak_ptr _largeObj; // We don't own this. -}; - - - -void problem4_2() { - // We directly construct 5 owners inside the vector to get around problem4_1: - std::vector owners(5); - - // Let's now fill the other vector with observers: - std::vector observers; - observers.reserve(owners.size()); - for (const auto& owner : owners) { - observers.emplace_back(owner); - } - - // Now let's destroy a few of the data owners: - owners.resize(3); - - std::cout << "Values of the observers:\n\t"; - for (const auto& observer : observers) { - std::cout << observer.getValue() << " "; - } - std::cout << "\n"; -} - - -int main() { - problem1(); - problem2(); - problem3(); - problem4_1(); - problem4_2(); -} From b066a81cf086e4e6a866b78c481487a5e1bbd4eb Mon Sep 17 00:00:00 2001 From: David Chamont Date: Sun, 29 Sep 2024 16:25:49 +0200 Subject: [PATCH 106/156] Small fix forgottent. --- exercises/ExercisesCheatSheet.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/exercises/ExercisesCheatSheet.md b/exercises/ExercisesCheatSheet.md index fa8c268e..555bebe1 100644 --- a/exercises/ExercisesCheatSheet.md +++ b/exercises/ExercisesCheatSheet.md @@ -137,14 +137,15 @@ The goal is to use STL algorithms. I would advise to start in this order : ### Smart pointers (directory: [`smartPointers`](smartPointers)) -Here we have four code snippets that will benefit from using smart pointers. +Here we have five code snippets that will benefit from using smart pointers. **Essentials**: Work on part 1 and 2 **Advanced**: Try all parts - `problem1` is a simple case of usage of `make_unique` with an observer pattern where the raw pointer should be used. - `problem2` is an example of a collection of pointers. Move semantic has to be used to transfer ownership of newly created objects to the container (alternatively, `emplace_back`). - `problem3` is an example of shared ownership where `std::shared_pointer` should be used. -- `problem4` demonstrates the usage of `shared_ptr` as class members. It has a second part where a `weak_ptr` can be used, but can be skipped if not enough time. +- `problem4` demonstrates the usage of `shared_ptr` as class members. +- `problem5` demonstrates the usage of `weak_ptr` can be used, but can be skipped if not enough time. ### std::optional (directory: [`optional`](optional)) Use std::optional to signify disallowed values in a computation. From a31c9d6cb31eaaeeeca06648fdb6e745fd90146f Mon Sep 17 00:00:00 2001 From: David Chamont Date: Sun, 29 Sep 2024 17:30:34 +0200 Subject: [PATCH 107/156] Inline static Co-authored-by: Stephan Hageboeck --- exercises/smartPointers/problem1.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/smartPointers/problem1.cpp b/exercises/smartPointers/problem1.cpp index 4524c0ee..89a0f383 100644 --- a/exercises/smartPointers/problem1.cpp +++ b/exercises/smartPointers/problem1.cpp @@ -29,7 +29,7 @@ struct LargeObject { // So to check for some potential memory leak, // we count the constructions and destructions - static std::size_t count ; + inline static std::size_t count = 0; LargeObject() { count++ ; } ~LargeObject() { count-- ; } From a652d289e2d14a1aecd27b9efa1c3985ed224e0e Mon Sep 17 00:00:00 2001 From: David Chamont Date: Sun, 29 Sep 2024 17:30:48 +0200 Subject: [PATCH 108/156] Update exercises/smartPointers/problem1.cpp Co-authored-by: Stephan Hageboeck --- exercises/smartPointers/problem1.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/exercises/smartPointers/problem1.cpp b/exercises/smartPointers/problem1.cpp index 89a0f383..90a522b8 100644 --- a/exercises/smartPointers/problem1.cpp +++ b/exercises/smartPointers/problem1.cpp @@ -35,7 +35,6 @@ struct LargeObject { } ; -std::size_t LargeObject::count = 0 ; // A function to do something with a large object. // Here we simulate that an error happens. From 42d7d1efd3247d87527cf8cd08f0d4d7056be742 Mon Sep 17 00:00:00 2001 From: David Chamont Date: Sun, 29 Sep 2024 17:31:04 +0200 Subject: [PATCH 109/156] Update exercises/smartPointers/problem1.cpp Co-authored-by: Stephan Hageboeck --- exercises/smartPointers/problem1.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/smartPointers/problem1.cpp b/exercises/smartPointers/problem1.cpp index 90a522b8..36035690 100644 --- a/exercises/smartPointers/problem1.cpp +++ b/exercises/smartPointers/problem1.cpp @@ -68,6 +68,6 @@ int main() { std::cerr<< "Terminated with exception: " << e.what() << "\n" ; } - std::cout<<"Forgotten large objects: "< Date: Sun, 29 Sep 2024 17:32:37 +0200 Subject: [PATCH 110/156] Add a shared_ptr Co-authored-by: Stephan Hageboeck --- exercises/smartPointers/problem3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/smartPointers/problem3.cpp b/exercises/smartPointers/problem3.cpp index be53a860..8b1a8f69 100644 --- a/exercises/smartPointers/problem3.cpp +++ b/exercises/smartPointers/problem3.cpp @@ -12,7 +12,7 @@ * * Most of the time, ownership can be solved by having one owner (with `std::unique_ptr`) and * one or more observers (raw pointers or references). Sometimes, we need to truly share data, - * though. Here is an example of a completely messed up ownership model. + * though. Here is an example of a completely messed up ownership model, which could be fixed using shared_ptr. * * Tasks * 1) Verify the mess by repeatedly running it using such a command like: From 808d1ab32841525f523c1f68c1e731a5524dcc48 Mon Sep 17 00:00:00 2001 From: David Chamont Date: Sun, 29 Sep 2024 17:40:43 +0200 Subject: [PATCH 111/156] Update exercises/smartPointers/problem3.cpp Co-authored-by: Stephan Hageboeck --- exercises/smartPointers/problem3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/smartPointers/problem3.cpp b/exercises/smartPointers/problem3.cpp index 8b1a8f69..c586c799 100644 --- a/exercises/smartPointers/problem3.cpp +++ b/exercises/smartPointers/problem3.cpp @@ -16,7 +16,7 @@ * * Tasks * 1) Verify the mess by repeatedly running it using such a command like: - * `while true; do ./problem3 2>&1 ; done` + * `while true; do ./problem3 ; done` * You should notice that the program regularly leaks. * 2) Fix the ownership model using `std::shared_ptr` ! * - Convert the vectors to holding `std::shared_ptr`. From b319545246cdabac12fbdf431663b48a475a14dd Mon Sep 17 00:00:00 2001 From: David Chamont Date: Sun, 29 Sep 2024 17:43:03 +0200 Subject: [PATCH 112/156] Apply problem1 fix to problem 2 and 3. --- exercises/smartPointers/problem1.cpp | 1 - exercises/smartPointers/problem2.cpp | 6 ++---- exercises/smartPointers/problem3.cpp | 6 ++---- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/exercises/smartPointers/problem1.cpp b/exercises/smartPointers/problem1.cpp index 36035690..1741aca7 100644 --- a/exercises/smartPointers/problem1.cpp +++ b/exercises/smartPointers/problem1.cpp @@ -35,7 +35,6 @@ struct LargeObject { } ; - // A function to do something with a large object. // Here we simulate that an error happens. diff --git a/exercises/smartPointers/problem2.cpp b/exercises/smartPointers/problem2.cpp index e8299bcf..20acea64 100644 --- a/exercises/smartPointers/problem2.cpp +++ b/exercises/smartPointers/problem2.cpp @@ -34,14 +34,12 @@ struct LargeObject { // So to check for some potential memory leak, // we count the constructions and destructions - static std::size_t count ; + inline static std::size_t count = 0; LargeObject() { count++ ; } ~LargeObject() { count-- ; } } ; -std::size_t LargeObject::count = 0 ; - // A factory function to create large objects. LargeObject * newLargeObject() { @@ -85,6 +83,6 @@ void doStuff() { int main() { doStuff() ; - std::cout<<"Forgotten large objects: "< Date: Sun, 29 Sep 2024 17:52:36 +0200 Subject: [PATCH 113/156] Remove useless removeMiddle from problem3, and apply previous fixes to solutions. --- exercises/smartPointers/problem3.cpp | 19 +++++-------------- .../smartPointers/solution/problem1.sol.cpp | 6 ++---- .../smartPointers/solution/problem2.sol.cpp | 6 ++---- .../smartPointers/solution/problem3.sol.cpp | 15 +++------------ 4 files changed, 12 insertions(+), 34 deletions(-) diff --git a/exercises/smartPointers/problem3.cpp b/exercises/smartPointers/problem3.cpp index 3b8a839a..8911fba1 100644 --- a/exercises/smartPointers/problem3.cpp +++ b/exercises/smartPointers/problem3.cpp @@ -12,7 +12,8 @@ * * Most of the time, ownership can be solved by having one owner (with `std::unique_ptr`) and * one or more observers (raw pointers or references). Sometimes, we need to truly share data, - * though. Here is an example of a completely messed up ownership model, which could be fixed using shared_ptr. + * though. Here is an example of a completely messed up ownership model, which could be + * fixed using shared_ptr. * * Tasks * 1) Verify the mess by repeatedly running it using such a command like: @@ -45,18 +46,8 @@ struct LargeObject { } ; // This removes an element from a non-owning vector, -// in the middle or in a random place. Such elements -// can by known in several vectors, so they must not -// be deleted. - -void removeMiddle( std::vector & collection ) { - - // MAKE YOUR CHANGES IN THIS FUNCTION - - auto middlePosition = collection.begin() + collection.size()/2 ; - collection.erase(middlePosition) ; - -} +// in a random place. Such elements can by known in +// several vectors, so they must not be deleted. void removeRandom( std::vector & collection, std::default_random_engine & engine ) { @@ -103,7 +94,7 @@ void doStuff() { // Random work with the objects - removeMiddle(objVector); + removeRandom(objVector,engine); removeRandom(objVectorCopy,engine); removeRandom(objVectorCopy,engine); // ... diff --git a/exercises/smartPointers/solution/problem1.sol.cpp b/exercises/smartPointers/solution/problem1.sol.cpp index a6c4e3fa..8fac5c6b 100644 --- a/exercises/smartPointers/solution/problem1.sol.cpp +++ b/exercises/smartPointers/solution/problem1.sol.cpp @@ -9,14 +9,12 @@ struct LargeObject { // So to check for some potential memory leak, // we count the constructions and destructions - static std::size_t count ; + inline static std::size_t count = 0 ; LargeObject() { count++ ; } ~LargeObject() { count-- ; } } ; -std::size_t LargeObject::count = 0 ; - void changeLargeObject( LargeObject & object ) { object.data[0] = 1. ; @@ -39,6 +37,6 @@ int main() { std::cerr<< "Terminated with exception: " << e.what() << "\n" ; } - std::cout<<"Forgotten large objects: "< newLargeObject() { auto object = std::make_unique() ; @@ -57,5 +55,5 @@ void doStuff() { int main() { doStuff() ; - std::cout<<"Forgotten large objects: "<>& collection) { - - auto middlePosition = collection.begin() + collection.size()/2; - collection.erase(middlePosition); - -} - void removeRandom(std::vector>& collection, std::default_random_engine & engine) { auto pos = collection.begin() + engine() % collection.size(); @@ -67,7 +58,7 @@ void doStuff() { // Random work with the objects - removeMiddle(objVector); + removeRandom(objVector,engine); removeRandom(objVectorCopy,engine); removeRandom(objVectorCopy,engine); // ... @@ -81,6 +72,6 @@ void doStuff() { int main() { doStuff() ; - std::cout<<"Forgotten large objects: "< Date: Sun, 29 Sep 2024 18:47:01 +0200 Subject: [PATCH 114/156] Cosmetic. --- exercises/ExercisesCheatSheet.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/exercises/ExercisesCheatSheet.md b/exercises/ExercisesCheatSheet.md index 555bebe1..752ee626 100644 --- a/exercises/ExercisesCheatSheet.md +++ b/exercises/ExercisesCheatSheet.md @@ -148,11 +148,13 @@ Here we have five code snippets that will benefit from using smart pointers. - `problem5` demonstrates the usage of `weak_ptr` can be used, but can be skipped if not enough time. ### std::optional (directory: [`optional`](optional)) + Use std::optional to signify disallowed values in a computation. 1. Use std::optional as return value of the mysqrt function. Use `nullopt_t` for negative arguments. Note that `return {}` will create a `nullopt_t` automatically. 2. Given that the return type changes, modify the square function accordingly to take into account cases where a `nullopt_t` is given as input. Note that `std::optional` can be directly used in an if statement as if it would be a boolean to check whether is value is present ### std::variant (directory: [`variant`](variant)) + Use the variant as an alternative to inheritance. The goal is to understand 1. That the base class is unnecessary when variant is used 2. That no dynamic allocations and polymorphism are necessary because the variant can directly be pushed into the vector From 4b7b88d2debbe8056530b4e260551f578bf121a0 Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Mon, 30 Sep 2024 14:15:45 +0200 Subject: [PATCH 115/156] mention std::expected as replacement for exceptions --- talk/morelanguage/exceptions.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/talk/morelanguage/exceptions.tex b/talk/morelanguage/exceptions.tex index df88885f..33771089 100644 --- a/talk/morelanguage/exceptions.tex +++ b/talk/morelanguage/exceptions.tex @@ -214,7 +214,7 @@ \end{itemize} \item \textit{don't} use exceptions to provide alternative/skip return values \begin{itemize} - \item you can use \cppinline{std::optional} or \cppinline{std::variant} + \item you can use \cppinline{std::optional}, \cppinline{std::variant} or \cppinline{std::expected} (\cpp23) \item avoid using the global C-style \cppinline{errno} \end{itemize} \item never throw in destructors From 157dd1feb53a6aab2a81517ded6d208696c76007 Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Mon, 30 Sep 2024 15:59:10 +0200 Subject: [PATCH 116/156] Update build-exercises.yml, drop atomix exercise (now merged into race condition) --- .github/workflows/build-exercises.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build-exercises.yml b/.github/workflows/build-exercises.yml index 8ca581e0..2c45afae 100644 --- a/.github/workflows/build-exercises.yml +++ b/.github/workflows/build-exercises.yml @@ -21,7 +21,6 @@ jobs: matrix: EXERCISE: - NAME: "asan" - - NAME: "atomic" - NAME: "basicTypes" - NAME: "callgrind" - NAME: "concepts" From 7c990174c578ab97ccfdf2cf5790af72a052bac4 Mon Sep 17 00:00:00 2001 From: David Chamont Date: Sun, 29 Sep 2024 22:11:10 +0200 Subject: [PATCH 117/156] Integrate atomic exercise as a final task in race exercise. --- exercises/atomic/CMakeLists.txt | 18 ---------- exercises/atomic/Makefile | 14 -------- exercises/atomic/README.md | 13 ------- exercises/atomic/atomic.cpp | 34 ------------------ exercises/atomic/solution/atomic.sol.cpp | 34 ------------------ exercises/race/CMakeLists.txt | 10 ++++-- exercises/race/Makefile | 9 +++-- exercises/race/README.md | 20 ++++++----- exercises/race/racing.cpp | 21 ++++++----- exercises/race/solution/racing.sol.cpp | 44 ------------------------ exercises/race/solution/racing.sol1.cpp | 39 +++++++++++++++++++++ exercises/race/solution/racing.sol2.cpp | 37 ++++++++++++++++++++ 12 files changed, 113 insertions(+), 180 deletions(-) delete mode 100644 exercises/atomic/CMakeLists.txt delete mode 100644 exercises/atomic/Makefile delete mode 100644 exercises/atomic/README.md delete mode 100644 exercises/atomic/atomic.cpp delete mode 100644 exercises/atomic/solution/atomic.sol.cpp delete mode 100644 exercises/race/solution/racing.sol.cpp create mode 100644 exercises/race/solution/racing.sol1.cpp create mode 100644 exercises/race/solution/racing.sol2.cpp diff --git a/exercises/atomic/CMakeLists.txt b/exercises/atomic/CMakeLists.txt deleted file mode 100644 index 91946368..00000000 --- a/exercises/atomic/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( atomic LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) - -# Figure out how to use the platform's thread capabilities. -find_package( Threads REQUIRED ) - -# Create the user's executable. -add_executable( atomic "atomic.cpp" ) -target_link_libraries( atomic PRIVATE Threads::Threads ) - -# Create the "solution executable". -add_executable( atomic.sol EXCLUDE_FROM_ALL "solution/atomic.sol.cpp" ) -target_link_libraries( atomic.sol PRIVATE Threads::Threads ) -add_dependencies( solution atomic.sol ) diff --git a/exercises/atomic/Makefile b/exercises/atomic/Makefile deleted file mode 100644 index 7462bc2b..00000000 --- a/exercises/atomic/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -PROGRAM_NAME=atomic - -all: $(PROGRAM_NAME) -solution: $(PROGRAM_NAME).sol - - -clean: - rm -f *o $(PROGRAM_NAME) *~ core $(PROGRAM_NAME).sol - -$(PROGRAM_NAME) : $(PROGRAM_NAME).cpp - ${CXX} -g -std=c++17 -O2 -pthread -Wall -Wextra -L. -o $@ $< - -$(PROGRAM_NAME).sol : solution/$(PROGRAM_NAME).sol.cpp - ${CXX} -g -std=c++17 -O2 -pthread -Wall -Wextra -L. -o $@ $< diff --git a/exercises/atomic/README.md b/exercises/atomic/README.md deleted file mode 100644 index 76b13aa2..00000000 --- a/exercises/atomic/README.md +++ /dev/null @@ -1,13 +0,0 @@ - -## Instructions - -You know this program already from "racing". -It tries to increment an integer 200 times in two threads. -Last time, we fixed the race condition using a lock, but now we'll try atomics. - -Tasks: -- Replace the counter 'a' by an atomic. - Run the program, and check for race conditions. -- Go back to 'racing', and check the execution time of the atomic vs the lock solution, - e.g. using `time ./atomic` - You might have to increase the number of tries if it completes too fast. diff --git a/exercises/atomic/atomic.cpp b/exercises/atomic/atomic.cpp deleted file mode 100644 index 713ef65f..00000000 --- a/exercises/atomic/atomic.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include -#include - -int main() { - int nError = 0; - - for (int j = 0; j < 1000; j++) { - int a = 0; - - // Increment the variable a 100 times: - auto inc100 = [&a](){ - for (int i = 0; i < 100; ++i) { - a++; - } - }; - - // Run with two threads - std::thread t1(inc100); - std::thread t2(inc100); - for (auto t : {&t1,&t2}) t->join(); - - // Check - if (a != 200) { - std::cout << "Race: " << a << ' '; - nError++; - } else { - std::cout << '.'; - } - } - std::cout << '\n'; - - return nError; -} diff --git a/exercises/atomic/solution/atomic.sol.cpp b/exercises/atomic/solution/atomic.sol.cpp deleted file mode 100644 index 8fc901ef..00000000 --- a/exercises/atomic/solution/atomic.sol.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include -#include - -int main() { - int nError = 0; - - for (int j = 0; j < 1000; j++) { - std::atomic a{0}; - - // Increment the variable a 100 times: - auto inc100 = [&a](){ - for (int i = 0; i < 100; ++i) { - a++; - } - }; - - // Run with two threads - std::thread t1(inc100); - std::thread t2(inc100); - for (auto t : {&t1,&t2}) t->join(); - - // Check - if (a != 200) { - std::cout << "Race: " << a << ' '; - nError++; - } else { - std::cout << '.'; - } - } - std::cout << '\n'; - - return nError; -} diff --git a/exercises/race/CMakeLists.txt b/exercises/race/CMakeLists.txt index c7415d6f..e5520481 100644 --- a/exercises/race/CMakeLists.txt +++ b/exercises/race/CMakeLists.txt @@ -13,6 +13,10 @@ add_executable( racing "racing.cpp" ) target_link_libraries( racing PRIVATE Threads::Threads ) # Create the "solution executable". -add_executable( racing.sol EXCLUDE_FROM_ALL "solution/racing.sol.cpp" ) -target_link_libraries( racing.sol PRIVATE Threads::Threads ) -add_dependencies( solution racing.sol ) +add_executable( racing.sol1 EXCLUDE_FROM_ALL "solution/racing.sol1.cpp" ) +target_link_libraries( racing.sol1 PRIVATE Threads::Threads ) +add_dependencies( solution1 racing.sol1 ) +add_executable( racing.sol2 EXCLUDE_FROM_ALL "solution/racing.sol2.cpp" ) +target_link_libraries( racing.sol2 PRIVATE Threads::Threads ) +add_dependencies( solution2 racing.sol2 ) +add_dependencies( solution solution1 solution2 ) diff --git a/exercises/race/Makefile b/exercises/race/Makefile index 4bf10084..129c7bd3 100644 --- a/exercises/race/Makefile +++ b/exercises/race/Makefile @@ -1,14 +1,17 @@ PROGRAM_NAME=racing all: $(PROGRAM_NAME) -solution: $(PROGRAM_NAME).sol +solution: $(PROGRAM_NAME).sol1 $(PROGRAM_NAME).sol2 clean: - rm -f *o $(PROGRAM_NAME) *~ core $(PROGRAM_NAME).sol + rm -f *o $(PROGRAM_NAME) *~ core $(PROGRAM_NAME).sol? $(PROGRAM_NAME) : $(PROGRAM_NAME).cpp ${CXX} ${CXXFLAGS} -g -std=c++17 -O2 -pthread -Wall -Wextra -L. -o $@ $< -$(PROGRAM_NAME).sol : solution/$(PROGRAM_NAME).sol.cpp +$(PROGRAM_NAME).sol1 : solution/$(PROGRAM_NAME).sol1.cpp + ${CXX} ${CXXFLAGS} -g -std=c++17 -O2 -pthread -Wall -Wextra -L. -o $@ $< + +$(PROGRAM_NAME).sol2 : solution/$(PROGRAM_NAME).sol2.cpp ${CXX} ${CXXFLAGS} -g -std=c++17 -O2 -pthread -Wall -Wextra -L. -o $@ $< diff --git a/exercises/race/README.md b/exercises/race/README.md index 95f6d2aa..3dc089a0 100644 --- a/exercises/race/README.md +++ b/exercises/race/README.md @@ -1,12 +1,16 @@ ## Instructions -* Compile and run the executable, see if it races - * If you have a bash shell, try `./run ./racing`, which keeps invoking the executable - until a race condition is detected -* (Optional) You can use `valgrind --tool=helgrind ./racing` to prove your assumption -* (Optional) If your operating system supports it, recompile with thread sanitizer. +The program `racing.cpp` is incrementing a shared integer many times, within several threads, which should lead to race conditions if no specific protection is used. The values of the global parameters `nThread`, `nInc` and `nRepeat` can be custommized for your own computer. + +Tasks +- Compile and run the executable, check it races. +- If you have a bash shell, try `./run ./racing`, which keeps invoking the executable until a race condition is detected. +- (Optional) You can use `valgrind --tool=helgrind ./racing` to prove your assumption +- (Optional) If your operating system supports it, recompile with thread sanitizer. With Makefile, use e.g. `make CXXFLAGS="-fsanitize=thread"` -* Use a mutex to fix the issue -* See the difference in execution time -* (Optional) Check again with `valgrind` or thread sanitizer if the problem is fixed +- Use a `std::mutex` to fix the issue. +- See the difference in execution time, for example with `time ./racing`. + You might have to increase `nRepeat` if it completes too fast, or lower it if it takes too long. +- (Optional) Check again with `valgrind` or thread sanitizer if the problem is fixed. +- Try to use `std::atomic` instead of the mutex, and compare the execution time. diff --git a/exercises/race/racing.cpp b/exercises/race/racing.cpp index 186131fe..5d8017dc 100644 --- a/exercises/race/racing.cpp +++ b/exercises/race/racing.cpp @@ -1,37 +1,40 @@ + #include #include #include /* - * This program tries to increment an integer 100 times from multiple threads. - * If the result comes out at 100*nThread, it stays silent, but it will print + * This program tries to increment an integer `nInc` times in `nThread` threads. + * If the result comes out at `nInc*nThread`, it stays silent, but it will print * an error if a race condition is detected. * If you don't see it racing, try ./run ./racing, which keeps invoking the * executable until a race condition is detected. */ -constexpr unsigned int nThread = 2; +constexpr std::size_t nThread = 10; +constexpr std::size_t nInc = 1000; +constexpr std::size_t nRepeat = 1000; int main() { int nError = 0; - for (int j = 0; j < 1000; j++) { + for (std::size_t j = 0; j < nRepeat; j++) { int a = 0; // Increment the variable a 100 times: - auto inc100 = [&a](){ - for (int i = 0; i < 100; ++i) { + auto increment = [&a](){ + for (std::size_t i = 0; i < nInc; ++i) { a++; } }; - // Start up all threads: + // Start up all threads std::vector threads; - for (unsigned int i = 0; i < nThread; ++i) threads.emplace_back(inc100); + for (std::size_t i = 0; i < nThread; ++i) threads.emplace_back(increment); for (auto & thread : threads) thread.join(); // Check - if (a != nThread * 100) { + if (a != nThread * nInc) { std::cerr << "Race detected! Result: " << a << '\n'; nError++; } diff --git a/exercises/race/solution/racing.sol.cpp b/exercises/race/solution/racing.sol.cpp deleted file mode 100644 index 8eb6fdf7..00000000 --- a/exercises/race/solution/racing.sol.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include -#include -#include - -/* - * This program tries to increment an integer 100 times from multiple threads. - * If the result comes out at 100*nThread, it stays silent, but it will print - * an error if a race condition is detected. - * To run it in a loop, use - * ./run ./racing.sol - */ - -constexpr unsigned int nThread = 2; - -int main() { - int nError = 0; - - for (int j = 0; j < 1000; j++) { - int a = 0; - std::mutex aMutex; - - // Increment the variable a 100 times: - auto inc100 = [&a,&aMutex](){ - for (int i = 0; i < 100; ++i) { - std::scoped_lock lock{aMutex}; - a++; - } - }; - - // Start up all threads: - std::vector threads; - for (unsigned int i = 0; i < nThread; ++i) threads.emplace_back(inc100); - for (auto & thread : threads) thread.join(); - - // Check - if (a != nThread * 100) { - std::cerr << "Race detected! Result: " << a << '\n'; - nError++; - } - } - - return nError; -} diff --git a/exercises/race/solution/racing.sol1.cpp b/exercises/race/solution/racing.sol1.cpp new file mode 100644 index 00000000..1d883406 --- /dev/null +++ b/exercises/race/solution/racing.sol1.cpp @@ -0,0 +1,39 @@ + +#include +#include +#include +#include + +constexpr std::size_t nThread = 10; +constexpr std::size_t nInc = 1000; +constexpr std::size_t nRepeat = 1000; + +int main() { + int nError = 0; + + for (std::size_t j = 0; j < nRepeat; j++) { + int a = 0; + std::mutex aMutex; + + // Increment the variable a 100 times: + auto increment = [&a,&aMutex](){ + for (std::size_t i = 0; i < nInc; ++i) { + std::scoped_lock lock{aMutex}; + a++; + } + }; + + // Start up all threads: + std::vector threads; + for (std::size_t i = 0; i < nThread; ++i) threads.emplace_back(increment); + for (auto & thread : threads) thread.join(); + + // Check + if (a != nThread * nInc) { + std::cerr << "Race detected! Result: " << a << '\n'; + nError++; + } + } + + return nError; +} diff --git a/exercises/race/solution/racing.sol2.cpp b/exercises/race/solution/racing.sol2.cpp new file mode 100644 index 00000000..2e3f2a98 --- /dev/null +++ b/exercises/race/solution/racing.sol2.cpp @@ -0,0 +1,37 @@ + +#include +#include +#include +#include + +constexpr std::size_t nThread = 10; +constexpr std::size_t nInc = 1000; +constexpr std::size_t nRepeat = 1000; + +int main() { + int nError = 0; + + for (std::size_t j = 0; j < nRepeat; j++) { + std::atomic a{0}; + + // Increment the variable a 100 times: + auto increment = [&a](){ + for (std::size_t i = 0; i < nInc; ++i) { + a++; + } + }; + + // Start up all threads + std::vector threads; + for (std::size_t i = 0; i < nThread; ++i) threads.emplace_back(increment); + for (auto & thread : threads) thread.join(); + + // Check + if (a != nThread * nInc) { + std::cerr << "Race detected! Result: " << a << '\n'; + nError++; + } + } + + return nError; +} From da4556305a05287db6758e1764ea791869d5e19c Mon Sep 17 00:00:00 2001 From: David Chamont Date: Mon, 30 Sep 2024 18:13:26 +0200 Subject: [PATCH 118/156] Rebase. --- exercises/CMakeLists.txt | 1 - exercises/ExerciseSchedule_AdvancedCourse.md | 2 -- exercises/ExercisesCheatSheet.md | 9 +++------ 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/exercises/CMakeLists.txt b/exercises/CMakeLists.txt index 36420d05..7f42f450 100644 --- a/exercises/CMakeLists.txt +++ b/exercises/CMakeLists.txt @@ -15,7 +15,6 @@ endif() # Include the exercises that (should) work on all platforms. add_subdirectory( hello ) add_subdirectory( asan ) -add_subdirectory( atomic ) add_subdirectory( basicTypes ) add_subdirectory( callgrind ) add_subdirectory( condition_variable ) diff --git a/exercises/ExerciseSchedule_AdvancedCourse.md b/exercises/ExerciseSchedule_AdvancedCourse.md index c6c55249..c4e31398 100644 --- a/exercises/ExerciseSchedule_AdvancedCourse.md +++ b/exercises/ExerciseSchedule_AdvancedCourse.md @@ -44,8 +44,6 @@ Day 3 ### Race conditions (directory: [`race`](race), [cheatSheet](ExercisesCheatSheet.md#race-conditions-directory-race)) -### Atomicity (directory: [`atomic`](atomic), [cheatSheet](ExercisesCheatSheet.md#atomicity-directory-atomic)) - ### Condition variables (directory: [`condition_variable`](condition_variable), [cheatSheet](ExercisesCheatSheet.md#condition-variables-directory-condition_variable)) ### Generic programming / templates (directory: [`templates`](templates), [cheatSheet](ExercisesCheatSheet.md#generic-programming--templates-directory-templates)) diff --git a/exercises/ExercisesCheatSheet.md b/exercises/ExercisesCheatSheet.md index 752ee626..9982dab2 100644 --- a/exercises/ExercisesCheatSheet.md +++ b/exercises/ExercisesCheatSheet.md @@ -344,13 +344,9 @@ Concurrency Exercises Typical race condition where a simple mutex and lock_guard "solves" the problem. -The second step is to look at the execution time and find out that it's not really a solution. One could then try an atomic and see the difference, although I do not introduce them in the course +The second step is to look at the execution time and find out that it's not really a solution. -### Atomicity (directory: [`atomic`](atomic)) - -Exactly the same race condition as above. Fix them using an `atomic`. - -*Optional*: Compare run times for lock and atomic solution. Those are likely not very different, as many locks are implemented using atomics. +Try then to use an `atomic` to solve the issue and compare the execution time with the lock solution. ### Condition variables (directory: [`condition_variable`](condition_variable)) @@ -358,6 +354,7 @@ Small example where 4 consumer threads are notified by a producer. 1. The production phase is not protected by a lock. 2. When the consumers are waking up, they don't release the lock that's tied to the condition variable, so they cannot wake up in parallel. + Python Exercises ---------------- From 5cf64e7155301b0e64544a15174ae13e8404b8bf Mon Sep 17 00:00:00 2001 From: David Chamont Date: Mon, 30 Sep 2024 17:48:31 +0200 Subject: [PATCH 119/156] Fix CMakeLists.txt --- exercises/race/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/exercises/race/CMakeLists.txt b/exercises/race/CMakeLists.txt index e5520481..07c789f8 100644 --- a/exercises/race/CMakeLists.txt +++ b/exercises/race/CMakeLists.txt @@ -15,8 +15,10 @@ target_link_libraries( racing PRIVATE Threads::Threads ) # Create the "solution executable". add_executable( racing.sol1 EXCLUDE_FROM_ALL "solution/racing.sol1.cpp" ) target_link_libraries( racing.sol1 PRIVATE Threads::Threads ) +add_custom_target( solution1 ) add_dependencies( solution1 racing.sol1 ) add_executable( racing.sol2 EXCLUDE_FROM_ALL "solution/racing.sol2.cpp" ) target_link_libraries( racing.sol2 PRIVATE Threads::Threads ) +add_custom_target( solution2 ) add_dependencies( solution2 racing.sol2 ) add_dependencies( solution solution1 solution2 ) From 19b5ef1253d7f460761ce34f558cf0a3fab9847b Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Wed, 2 Oct 2024 09:50:28 +0200 Subject: [PATCH 120/156] Fixed missing line in std::optional example --- talk/morelanguage/morestl.tex | 1 + 1 file changed, 1 insertion(+) diff --git a/talk/morelanguage/morestl.tex b/talk/morelanguage/morestl.tex index c5cf8ce7..4ead2b2b 100644 --- a/talk/morelanguage/morestl.tex +++ b/talk/morelanguage/morestl.tex @@ -102,6 +102,7 @@ return in; // equiv. to optional{in}; return {}; // or: return std::nullopt; (empty opt.) } + auto v = parse_phone(...); if (v) { // or: v.has_value() process_phone(v.value()); // or: *v (unchecked) v->call(); // calls Phone::call() (unchecked) From 34be19c2ef1e28b1ddb43cabc87ebdcde72f4cd1 Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Wed, 2 Oct 2024 11:42:17 +0200 Subject: [PATCH 121/156] Drop call to request_stop on slide of jthread --- talk/concurrency/threadsasync.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/talk/concurrency/threadsasync.tex b/talk/concurrency/threadsasync.tex index 8b0a3990..b33d6654 100644 --- a/talk/concurrency/threadsasync.tex +++ b/talk/concurrency/threadsasync.tex @@ -64,7 +64,7 @@ void bar() {...} int main() { std::jthread t1{foo}; - std::jthread t2{bar}; t2.request_stop(); + std::jthread t2{bar}; // No join required return 0; } From 4d4a3446e6bb68cf1a058615e9e62f048c070b52 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 23:45:32 +0000 Subject: [PATCH 122/156] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v4.6.0 → v5.0.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.6.0...v5.0.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8df4a34f..6ee123be 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v5.0.0 hooks: - id: check-added-large-files - id: check-case-conflict From 0926603f74868c9c538a4a1d42d06d81f4657484 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Wed, 2 Oct 2024 11:35:23 +0200 Subject: [PATCH 123/156] Add box on namespace aliases as suggested by Attila. --- talk/basicconcepts/scopesnamespaces.tex | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/talk/basicconcepts/scopesnamespaces.tex b/talk/basicconcepts/scopesnamespaces.tex index a9abfab5..c3f382f2 100644 --- a/talk/basicconcepts/scopesnamespaces.tex +++ b/talk/basicconcepts/scopesnamespaces.tex @@ -159,8 +159,7 @@ \begin{frame}[fragile] \frametitlecpp[17]{Nested namespaces} - Easier way to declare nested namespaces - \begin{alertblock}{\cpp98} + \begin{alertblock}{\cpp98: Old way to declare nested namespaces} \begin{cppcode*}{} namespace A { namespace B { @@ -171,13 +170,18 @@ } \end{cppcode*} \end{alertblock} - \begin{exampleblock}{\cpp17} + \begin{exampleblock}{\cpp17: Nested declaration} \begin{cppcode*}{} namespace A::B::C { //... } \end{cppcode*} \end{exampleblock} + \begin{exampleblock}{\cpp17: Namespace alias} + \begin{cppcode*}{} + namespace ABC = A::B::C; + \end{cppcode*} + \end{exampleblock} \end{frame} \begin{advanced} From e7592ed694f8ef10066a8a65dd6ca85e3e5ab536 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Wed, 2 Oct 2024 11:36:28 +0200 Subject: [PATCH 124/156] Clarify that value-init is used when STL enlarges containers. --- talk/morelanguage/initialization.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/talk/morelanguage/initialization.tex b/talk/morelanguage/initialization.tex index aa683f0a..f04c9962 100644 --- a/talk/morelanguage/initialization.tex +++ b/talk/morelanguage/initialization.tex @@ -160,7 +160,7 @@ \item Unless \cppinline{T} has a \cppinline{std::initializer_list} constructor that you do not want to call! \item Be wary of \cppinline{std::vector}! \end{itemize} - \item The STL value initializes when creating new user objects + \item The STL uses value initialisation when resizing containers \begin{itemize} \item E.g. \cppinline{vec.resize(vec.size() + 10);} \end{itemize} From a2fec7d4f9fc6a43d5fc1d89ba888c5fc545acdc Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 4 Oct 2024 12:02:24 +0200 Subject: [PATCH 125/156] Make comparison slightly more readable by inserting spaces. --- talk/expert/cpp20concepts.tex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/talk/expert/cpp20concepts.tex b/talk/expert/cpp20concepts.tex index 669c2256..7dd807ad 100644 --- a/talk/expert/cpp20concepts.tex +++ b/talk/expert/cpp20concepts.tex @@ -27,7 +27,7 @@ >> bool equal( T e1, T e2 ) { - return std::abs(e1-e2)::epsilon(); + return std::abs(e1-e2) < std::numeric_limits::epsilon(); } ... equal(10,5+5) ... \end{cppcode*} @@ -62,7 +62,7 @@ template requires std::is_floating_point_v bool equal( T e1, T e2 ) { - return std::abs(e1-e2)::epsilon(); + return std::abs(e1-e2) < std::numeric_limits::epsilon(); } ... equal(10,5+5) ... \end{cppcode*} @@ -119,7 +119,7 @@ template< typename T> concept MyFloatingPoint = std::is_floating_point_v && - std::numeric_limits::epsilon()>0; + std::numeric_limits::epsilon() > 0; template requires MyFloatingPoint From 217200d65c7f68990bb1096228b0ab006e83527b Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Wed, 15 Jan 2025 17:18:12 +0100 Subject: [PATCH 126/156] Fix a compile error by pulling a code block out of itemize. --- talk/morelanguage/lambda.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/talk/morelanguage/lambda.tex b/talk/morelanguage/lambda.tex index 168fc295..ee7cee72 100644 --- a/talk/morelanguage/lambda.tex +++ b/talk/morelanguage/lambda.tex @@ -287,11 +287,11 @@ \end{itemize} \end{block} \begin{block}{Explicit template parameters (\cpp20)} - \begin{itemize} \begin{cppcode*}{linenos=false,gobble=4} auto add = [](T a, T b) { return a + b; }; \end{cppcode*} + \begin{itemize} \item The types of \cppinline{a} and \cppinline{b} must be the same. \end{itemize} \end{block} From d3323b33631ff9f60776481765bec5bd2a06bc2c Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Thu, 13 Feb 2025 10:59:58 +0100 Subject: [PATCH 127/156] Move to xelatex. pdflatx runs out of memory with minted-v3. Moving to xelatex fixed this. --- .github/workflows/build-slides.yml | 2 ++ talk/Makefile | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-slides.yml b/.github/workflows/build-slides.yml index 47e78b98..e2814296 100644 --- a/.github/workflows/build-slides.yml +++ b/.github/workflows/build-slides.yml @@ -28,6 +28,7 @@ jobs: with: root_file: C++Course.tex latexmk_shell_escape: true + latexmk_use_xelatex: true args: -pdf -interaction=nonstopmode -halt-on-error -usepretex=\def\makebasic{} working_directory: talk extra_system_packages: "py-pygments" @@ -37,6 +38,7 @@ jobs: with: root_file: C++Course.tex latexmk_shell_escape: true + latexmk_use_xelatex: true args: -pdf -interaction=nonstopmode -halt-on-error working_directory: talk extra_system_packages: "py-pygments" diff --git a/talk/Makefile b/talk/Makefile index ad26716e..7dc47044 100644 --- a/talk/Makefile +++ b/talk/Makefile @@ -1,7 +1,7 @@ all: C++Course.pdf LATEXMK=latexmk -OPTIONS=-pdf -shell-escape -halt-on-error +OPTIONS=-pdf -xelatex -shell-escape -halt-on-error essentials: all essentials: OPTIONS+=-usepretex='\def\makebasic{}' From 1851121420462ec0167ce0e97245ea4beb647380 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Thu, 13 Feb 2025 11:30:05 +0100 Subject: [PATCH 128/156] Upgrade exercise runners to macos-latest. --- .github/workflows/build-exercises.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/build-exercises.yml b/.github/workflows/build-exercises.yml index 2c45afae..9e3f3942 100644 --- a/.github/workflows/build-exercises.yml +++ b/.github/workflows/build-exercises.yml @@ -61,8 +61,7 @@ jobs: GENERATOR: -G "Unix Makefiles" env: CXX: g++-11 - # We temporarily need to hardcode macos-12, because "-latest" resolves to 11 - - OS: "macos-12" + - OS: "macos-latest" GENERATOR: -G "Xcode" - OS: "windows-latest" GENERATOR: From 3553a2d8198fe9f3078d4f3c1df0d196d19cb30a Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Thu, 13 Feb 2025 11:14:21 +0100 Subject: [PATCH 129/156] Used autogobble everywhere in minted by default And dropped (most of) the manual gobble= in the rest of the slides this has also fixed a couple of bad indentations here and there --- talk/basicconcepts/classenum.tex | 22 ++++----- talk/basicconcepts/control.tex | 2 +- talk/basicconcepts/coresyntax.tex | 2 +- talk/basicconcepts/functions.tex | 16 +++--- talk/basicconcepts/references.tex | 2 +- talk/basicconcepts/scopesnamespaces.tex | 8 +-- talk/concurrency/atomic.tex | 4 +- talk/concurrency/condition.tex | 4 +- talk/concurrency/mutexes.tex | 6 +-- talk/concurrency/threadsasync.tex | 4 +- talk/expert/coroutines.tex | 34 ++++++------- talk/expert/cpp20concepts.tex | 14 +++--- talk/expert/modules.tex | 60 +++++++++++------------ talk/expert/perfectforwarding.tex | 6 +-- talk/expert/sfinae.tex | 6 +-- talk/morelanguage/exceptions.tex | 24 ++++----- talk/morelanguage/lambda.tex | 30 ++++++------ talk/morelanguage/morestl.tex | 8 +-- talk/morelanguage/move.tex | 10 ++-- talk/morelanguage/raii.tex | 14 +++--- talk/morelanguage/random.tex | 2 +- talk/morelanguage/ranges.tex | 4 +- talk/morelanguage/stl.tex | 6 +-- talk/morelanguage/templates.tex | 18 +++---- talk/objectorientation/adl.tex | 16 +++--- talk/objectorientation/advancedoo.tex | 18 +++---- talk/objectorientation/constructors.tex | 8 +-- talk/objectorientation/inheritance.tex | 16 +++--- talk/objectorientation/objectsclasses.tex | 10 ++-- talk/objectorientation/operators.tex | 2 +- talk/objectorientation/typecasting.tex | 4 +- talk/python/ctypes.tex | 2 +- talk/python/marryingcandcpp.tex | 6 +-- talk/python/modulewriting.tex | 2 +- talk/setup.tex | 10 ++-- talk/tools/doxygen.tex | 4 +- talk/tools/sanitizers.tex | 6 +-- talk/tools/vcs.tex | 2 +- 38 files changed, 206 insertions(+), 206 deletions(-) diff --git a/talk/basicconcepts/classenum.tex b/talk/basicconcepts/classenum.tex index b990f978..6f4ebf33 100644 --- a/talk/basicconcepts/classenum.tex +++ b/talk/basicconcepts/classenum.tex @@ -6,7 +6,7 @@ \center ``members'' grouped together under one name \end{mdframed} \begin{multicols}{2} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} struct Individual { unsigned char age; float weight; @@ -21,7 +21,7 @@ }; \end{cppcode*} \columnbreak - \begin{cppcode*}{gobble=2,firstnumber=14} + \begin{cppcode*}{firstnumber=14} Individual *ptr = &student; ptr->age = 25; // same as: (*ptr).age = 25; @@ -56,7 +56,7 @@ \center ``members'' packed together at same memory location \end{mdframed} \begin{multicols}{2} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} union Duration { int seconds; short hours; @@ -104,7 +104,7 @@ \end{itemize} \end{block} \begin{multicols}{2} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} enum VehicleType { BIKE, // 0 @@ -114,7 +114,7 @@ VehicleType t = CAR; \end{cppcode*} \columnbreak - \begin{cppcode*}{gobble=2,firstnumber=8} + \begin{cppcode*}{firstnumber=8} enum VehicleType : int { // C++11 BIKE = 3, @@ -158,7 +158,7 @@ \begin{frame}[fragile] \frametitlecpp[98]{More sensible example} \begin{multicols}{2} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} enum class ShapeType { Circle, Rectangle @@ -171,7 +171,7 @@ \end{cppcode*} \columnbreak \pause - \begin{cppcode*}{gobble=2,firstnumber=10} + \begin{cppcode*}{firstnumber=10} struct Shape { ShapeType type; union { @@ -183,7 +183,7 @@ \end{multicols} \pause \begin{multicols}{2} - \begin{cppcode*}{gobble=2,firstnumber=17} + \begin{cppcode*}{firstnumber=17} Shape s; s.type = ShapeType::Circle; @@ -191,7 +191,7 @@ \end{cppcode*} \columnbreak - \begin{cppcode*}{gobble=2,firstnumber=20} + \begin{cppcode*}{firstnumber=20} Shape t; t.type = Shapetype::Rectangle; @@ -205,14 +205,14 @@ \frametitle{typedef and using \hfill \cpp98 / \cpp11} Used to create type aliases \begin{alertblock}{\cpp98} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} typedef std::uint64_t myint; myint count = 17; typedef float position[3]; \end{cppcode*} \end{alertblock} \begin{exampleblock}{\cpp11} - \begin{cppcode*}{gobble=2,firstnumber=4} + \begin{cppcode*}{firstnumber=4} using myint = std::uint64_t; myint count = 17; using position = float[3]; diff --git a/talk/basicconcepts/control.tex b/talk/basicconcepts/control.tex index 3dca64cc..c2004a0c 100644 --- a/talk/basicconcepts/control.tex +++ b/talk/basicconcepts/control.tex @@ -77,7 +77,7 @@ \begin{frame}[fragile] \frametitlecpp[98]{Control structures: switch} \begin{block}{Syntax} - \begin{cppcode*}{gobble=0} + \begin{cppcode*}{} switch(identifier) { case c1 : statements1; break; case c2 : statements2; break; diff --git a/talk/basicconcepts/coresyntax.tex b/talk/basicconcepts/coresyntax.tex index 60ca43bb..ce5d7552 100644 --- a/talk/basicconcepts/coresyntax.tex +++ b/talk/basicconcepts/coresyntax.tex @@ -169,7 +169,7 @@ \item Custom conversion and promotion rules \end{itemize} \end{block} - \begin{cppcode*}{gobble=4} + \begin{cppcode*}{} #include // may define these: std::float16_t = 3.14f16; // 16 (1+5+10) bit float diff --git a/talk/basicconcepts/functions.tex b/talk/basicconcepts/functions.tex index 24ea9f40..6ef973f5 100644 --- a/talk/basicconcepts/functions.tex +++ b/talk/basicconcepts/functions.tex @@ -3,7 +3,7 @@ \begin{frame}[fragile] \frametitlecpp[98]{Functions} \begin{multicols}{2} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} // with return type int square(int a) { return a * a; @@ -16,7 +16,7 @@ } \end{cppcode*} \columnbreak - \begin{cppcode*}{gobble=2,firstnumber=11} + \begin{cppcode*}{firstnumber=11} // no return void log(char* msg) { std::cout << msg; @@ -43,7 +43,7 @@ \begin{frame}[fragile] \frametitlecpp[98]{Function default arguments} \begin{multicols}{2} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} // must be the trailing // argument int add(int a, @@ -55,7 +55,7 @@ \end{cppcode*} \columnbreak - \begin{cppcode*}{gobble=2,firstnumber=11} + \begin{cppcode*}{firstnumber=11} // multiple default // arguments are possible int add(int a = 2, @@ -361,7 +361,7 @@ \end{itemize} \end{block} \begin{exampleblock}{} - \begin{cppcode*}{gobble=6} + \begin{cppcode*}{} int sum(int b); // 1 int sum(int b, int c); // 2, ok, overload // float sum(int b, int c); // disallowed @@ -399,7 +399,7 @@ \end{itemize} \end{goodpractice} \begin{exampleblock}{Example: Good} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} /// Count number of dilepton events in data. /// \param d Dataset to search. unsigned int countDileptons(Data &d) { @@ -413,7 +413,7 @@ \begin{onlyenv}<2-> \begin{alertblock}{Example: don't! Everything in one long function} \begin{multicols}{2} - \begin{cppcode*}{gobble=6} + \begin{cppcode*}{} unsigned int runJob() { // Step 1: data Data data; @@ -430,7 +430,7 @@ for (....) { \end{cppcode*} \columnbreak - \begin{cppcode*}{gobble=6,firstnumber=last} + \begin{cppcode*}{firstnumber=last} if (...) { data.erase(...); } diff --git a/talk/basicconcepts/references.tex b/talk/basicconcepts/references.tex index a8fa13c8..40e775fc 100644 --- a/talk/basicconcepts/references.tex +++ b/talk/basicconcepts/references.tex @@ -11,7 +11,7 @@ \end{block} \begin{exampleblock}{Example:} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} int i = 2; int &iref = i; // access to i iref = 3; // i is now 3 diff --git a/talk/basicconcepts/scopesnamespaces.tex b/talk/basicconcepts/scopesnamespaces.tex index c3f382f2..c49976bd 100644 --- a/talk/basicconcepts/scopesnamespaces.tex +++ b/talk/basicconcepts/scopesnamespaces.tex @@ -122,7 +122,7 @@ \item They can be embedded to create hierarchies (separator is '::') \end{itemize} \begin{multicols}{2} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} int a; namespace n { int a; // no clash @@ -138,7 +138,7 @@ } \end{cppcode*} \columnbreak - \begin{cppcode*}{gobble=2,firstnumber=14} + \begin{cppcode*}{firstnumber=14} namespace p { // reopen p void f() { p::a = 6; @@ -207,7 +207,7 @@ \end{itemize} \end{block} \begin{alertblock}{Supersedes static} - \begin{cppcode*}{gobble=2,firstnumber=4} + \begin{cppcode*}{firstnumber=4} static int localVar; // equivalent C code \end{cppcode*} \end{alertblock} @@ -226,7 +226,7 @@ \end{cppcode*} \end{alertblock} \begin{alertblock}{Never use in headers at global scope!} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} #include "PoorlyWritten.h" // using namespace std; struct array { ... }; array a; // Error: name clash with std::array diff --git a/talk/concurrency/atomic.tex b/talk/concurrency/atomic.tex index fc2e3081..0580a041 100644 --- a/talk/concurrency/atomic.tex +++ b/talk/concurrency/atomic.tex @@ -96,7 +96,7 @@ \end{itemize} \end{block} \begin{exampleblock}{} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} int a{0}; std::thread t1([&]{ std::atomic_ref r{a}; r++;}); std::thread t2([&]{ std::atomic_ref{a}++; }); @@ -106,7 +106,7 @@ \end{cppcode*} \end{exampleblock} \begin{alertblock}{Don't mix concurrent atomic and non-atomic access} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} std::thread t3([&]{ std::atomic_ref{a}++; }); a += 2; // data race t3.join(); diff --git a/talk/concurrency/condition.tex b/talk/concurrency/condition.tex index 86c1be82..d688408a 100644 --- a/talk/concurrency/condition.tex +++ b/talk/concurrency/condition.tex @@ -81,7 +81,7 @@ \end{overprint} \begin{alertblock}{Na\"ive waiting} - \begin{cppcode*}{gobble=2,highlightlines=3} + \begin{cppcode*}{highlightlines=3} auto processData = [&](){ std::unique_lock lock{mutex}; cond.wait(lock, [&](){ return data.isReady(); }); @@ -101,7 +101,7 @@ \end{block} \begin{exampleblock}{Correct waiting} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} auto processData = [&](){ { std::unique_lock lock{mutex}; diff --git a/talk/concurrency/mutexes.tex b/talk/concurrency/mutexes.tex index d190e0aa..5721e8d6 100644 --- a/talk/concurrency/mutexes.tex +++ b/talk/concurrency/mutexes.tex @@ -126,7 +126,7 @@ \end{itemize} \end{goodpractice} \begin{exampleblock}{} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} void function(...) { // uncritical work ... { @@ -210,7 +210,7 @@ \end{itemize} \end{block} \begin{exampleblock}{} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} Data data; std::shared_mutex mutex; auto reader = [&](){ std::shared_lock lock{mutex}; @@ -236,7 +236,7 @@ \end{itemize} \end{block} \begin{exampleblock}{} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} void worker(const int id, std::ostream & os); void func() { std::osyncstream synccout1{std::cout}; diff --git a/talk/concurrency/threadsasync.tex b/talk/concurrency/threadsasync.tex index b33d6654..26a16357 100644 --- a/talk/concurrency/threadsasync.tex +++ b/talk/concurrency/threadsasync.tex @@ -11,7 +11,7 @@ \end{block} \begin{exampleblock}{Example code} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} void foo() {...} void bar() {...} int main() { @@ -59,7 +59,7 @@ \end{goodpractice} \begin{exampleblock}{Example with jthread} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} void foo() {...} void bar() {...} int main() { diff --git a/talk/expert/coroutines.tex b/talk/expert/coroutines.tex index 23004099..dc19993e 100644 --- a/talk/expert/coroutines.tex +++ b/talk/expert/coroutines.tex @@ -5,14 +5,14 @@ \subsection{Coroutines} \begin{block}{The generator use case (one of several)} In python one can write {\scriptsize - \begin{pythoncode*}{gobble=2} + \begin{pythoncode*}{} for i in range(0, 10): print(i) \end{pythoncode*} } What about it in \cpp? {\scriptsize - \begin{cppcode*}{gobble=2, firstnumber=3} + \begin{cppcode*}{firstnumber=3} someType range(int first, int last) { ... } for (auto i : range(0, 10)) { std::cout << i << "\n"; @@ -35,7 +35,7 @@ \subsection{Coroutines} \frametitlecpp[20]{What \cpp20 allows} \begin{exampleblock}{Interesting part of the implementation (see \href{https://en.cppreference.com/w/cpp/coroutine/coroutine\_handle\#Example}{\color{blue!50!white}cppreference})} {\scriptsize - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} template Generator range(T first, const T last) { while (first < last) { @@ -92,7 +92,7 @@ \subsection{Coroutines} \frametitlecpp[20]{Minimal code} \begin{block}{Definition of an empty coroutine} {\scriptsize - \begin{cppcode*}{gobble=2, firstnumber=3} + \begin{cppcode*}{firstnumber=3} #include struct Task { struct promise_type { @@ -184,7 +184,7 @@ \subsection{Coroutines} \end{block} \begin{exampleblock}{Code} {\scriptsize - \begin{cppcode*}{gobble=4} + \begin{cppcode*}{} Task myCoroutine() { std::cout << "Step 1 of coroutine\n"; co_await std::suspend_always{}; @@ -214,7 +214,7 @@ \subsection{Coroutines} \end{block} \begin{exampleblock}{Code} {\scriptsize - \begin{cppcode*}{gobble=4} + \begin{cppcode*}{} struct Task { struct promise_type { Task get_return_object() { @@ -235,7 +235,7 @@ \subsection{Coroutines} \frametitlecpp[20]{Resuming a coroutine} \scriptsize \begin{exampleblockGB}{User code}{https://godbolt.org/z/qx46Pa4v3}{Coroutine resumption} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} Task myCoroutine() { std::cout << "Step 1 of coroutine\n"; co_await std::suspend_always{}; @@ -254,7 +254,7 @@ \subsection{Coroutines} \end{cppcode*} \end{exampleblockGB} \begin{block}{} - \begin{minted}[gobble=4]{text} + \begin{minted}{text} Step 1 of coroutine In main, between Step 1 and 2 Step 2 of coroutine @@ -278,7 +278,7 @@ \subsection{Coroutines} \begin{itemize} \item which requires another piece of code in \cppinline{Task}, e.g. {\scriptsize - \begin{cppcode*}{gobble=8,linenos=false} + \begin{cppcode*}{linenos=false} ~Task() { if (h_) h_.destroy(); } \end{cppcode*} } @@ -304,7 +304,7 @@ \subsection{Coroutines} \end{block} \begin{exampleblock}{Typical code} {\scriptsize - \begin{cppcode*}{gobble=4} + \begin{cppcode*}{} template struct Task { struct promise_type { T value_; @@ -325,7 +325,7 @@ \subsection{Coroutines} \frametitlecpp[20]{\texttt{co\_yield} - generator behavior} \begin{block}{Generator behavior - more boiler plate code} {\scriptsize - \begin{cppcode*}{gobble=4} + \begin{cppcode*}{} template struct Task { struct iterator { @@ -352,7 +352,7 @@ \subsection{Coroutines} \frametitlecpp[20]{\texttt{co\_yield} - final usage} \begin{exampleblockGB}{Finally, we can use the generator nicely}{https://godbolt.org/z/6bbrYrss5}{\texttt{co\_yield}} {\scriptsize - \begin{cppcode*}{gobble=4} + \begin{cppcode*}{} Task range(int first, int last) { while (first != last) { co_yield first++; @@ -371,7 +371,7 @@ \subsection{Coroutines} \item we should pause in \cppinline{initial_suspend} \end{itemize} {\scriptsize - \begin{cppcode*}{gobble=4,firstnumber=10} + \begin{cppcode*}{firstnumber=10} struct Task { struct promise_type { ... @@ -387,7 +387,7 @@ \subsection{Coroutines} \begin{frame}[fragile] \frametitlecpp[20]{Laziness allows for infinite ranges} \begin{exampleblockGB}{Generators do not need to be finite}{https://godbolt.org/z/MP6qdGWYe}{Infinite generator} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} Task range(int first) { while (true) { co_yield first++; @@ -404,7 +404,7 @@ \subsection{Coroutines} \frametitlecpp[20]{Real life example} \begin{exampleblockGB}{A Fibonacci generator, from \cpprefLink{https://en.cppreference.com/w/cpp/language/coroutines}}{https://godbolt.org/z/3Pev1M8se}{Fibonacci generator} \scriptsize - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} Task fibonacci(unsigned n) { if (n==0) co_return; co_yield 0; @@ -497,7 +497,7 @@ \subsection{Coroutines} \frametitlecpp[20]{\texttt{awaiter} example} \begin{exampleblockGB}{Switch to new thread, from \cpprefLink{https://en.cppreference.com/w/cpp/language/coroutines}}{https://godbolt.org/z/K7svE4P7s}{Thread switching} \scriptsize - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} auto switch_to_new_thread(std::jthread& out) { struct awaiter { std::jthread* th; @@ -531,7 +531,7 @@ \subsection{Coroutines} \raggedright \begin{block}{Output} \scriptsize - \begin{minted}[gobble=9]{text} + \begin{minted}{text} Started on thread: 140144191063872 New thread ID: 140144191059712 Resumed on thread: 140144191059712 diff --git a/talk/expert/cpp20concepts.tex b/talk/expert/cpp20concepts.tex index 7dd807ad..f77a9657 100644 --- a/talk/expert/cpp20concepts.tex +++ b/talk/expert/cpp20concepts.tex @@ -115,7 +115,7 @@ \end{block} \begin{exampleblock}{A new keyword: \texttt{concept}} \small - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} template< typename T> concept MyFloatingPoint = std::is_floating_point_v && @@ -138,7 +138,7 @@ \end{block} \begin{exampleblock}{} \small - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} template bool equal( T e1, T e2 ) { return std::abs(e1-e2)::epsilon(); @@ -151,7 +151,7 @@ \end{itemize} \end{block} \begin{exampleblock}{Example code} - \begin{cppcode*}{firstnumber=4,gobble=2} + \begin{cppcode*}{firstnumber=4} MyFloatingPoint auto f = 3.14f; MyFloatingPoint auto d = 3.14; MyFloatingPoint auto i = 3; // compile error @@ -175,7 +175,7 @@ \end{block} \begin{exampleblock}{} \small - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} // no template <...> here! bool equal( MyFloatingPoint auto e1, MyFloatingPoint auto e2 ) { @@ -199,7 +199,7 @@ \end{block} \begin{exampleblock}{E.g.: the floating point concept} \small - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} #include bool equal( std::floating_point auto e1, std::floating_point auto e2 ) { @@ -223,7 +223,7 @@ \end{block} \begin{exampleblock}{Using concepts with \texttt{if constexpr}} \small - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} template bool equal( T e1, T e2 ) { @@ -250,7 +250,7 @@ \end{block} \begin{exampleblock}{Practically} \small - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} template concept StreamableAndComparableNumber = requires( T v1, T v2, std::ostream os ) { diff --git a/talk/expert/modules.tex b/talk/expert/modules.tex index 29021119..5ff95577 100644 --- a/talk/expert/modules.tex +++ b/talk/expert/modules.tex @@ -28,7 +28,7 @@ \begin{frame}[fragile] \frametitlecpp[20]{Writing modules} \begin{exampleblock}{ratio.cpp} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} export module math; import ; namespace utils { // ns. and module names orthogonal @@ -39,7 +39,7 @@ \end{cppcode*} \end{exampleblock} \begin{exampleblock}{main.cpp} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} import ; import math; int main() { @@ -66,7 +66,7 @@ \begin{frame}[fragile] \frametitlecpp[20]{Writing modules} \begin{exampleblock}{What to export} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} export module math; export void f(); // function @@ -89,7 +89,7 @@ \begin{frame}[fragile] \frametitlecpp[20]{Writing modules} \begin{alertblock}{What not to export} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} export module math; namespace { @@ -110,14 +110,14 @@ \begin{frame}[fragile] \frametitlecpp[20]{Visibility and reachability} \begin{exampleblock}{ratio.cpp} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} export module math; struct Ratio { float num, denom; }; export Ratio golden() { ... } // golden is visible \end{cppcode*} \end{exampleblock} \begin{exampleblock}{main.cpp} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} import math; import ; int main() { @@ -136,7 +136,7 @@ \frametitlecpp[20]{Module structure} \begin{exampleblock}{} \small - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} module; // global module fragment (opt.) #include // only preprocessor // ... // statements allowed @@ -160,7 +160,7 @@ \begin{frame}[fragile] \frametitlecpp[20]{Module structure} \begin{alertblock}{Pitfall} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} export module math; #include import ; @@ -174,7 +174,7 @@ \end{itemize} \end{block} \begin{exampleblock}{Put includes into global module fragment} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} module; #include export module math; @@ -190,7 +190,7 @@ Like with header files, we can split interface and implementation: \end{block} \begin{exampleblock}{Interface} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} export module math; export struct S { ... }; @@ -198,7 +198,7 @@ \end{cppcode*} \end{exampleblock} \begin{exampleblock}{Implementation} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} module; #include module math; @@ -219,7 +219,7 @@ \begin{columns}[t] \begin{column}{.45\textwidth} \begin{exampleblock}{Module one} - \begin{cppcode*}{gobble=6} + \begin{cppcode*}{} export module one; export struct S { ... }; @@ -228,7 +228,7 @@ \end{column} \begin{column}{.45\textwidth} \begin{exampleblock}{Module two} - \begin{cppcode*}{gobble=6} + \begin{cppcode*}{} export module two; import ; @@ -241,7 +241,7 @@ \begin{columns}[t] \begin{column}{.45\textwidth} \begin{exampleblock}{Module three} - \begin{cppcode*}{gobble=6} + \begin{cppcode*}{} export module three; import one; export import two; @@ -252,7 +252,7 @@ \end{column} \begin{column}{.45\textwidth} \begin{exampleblock}{Module four} - \begin{cppcode*}{gobble=6} + \begin{cppcode*}{} export module four; import three; // b and f visible @@ -273,7 +273,7 @@ \begin{columns}[t] \begin{column}{.4\textwidth} \begin{exampleblock}{Primary module interface} - \begin{cppcode*}{gobble=6} + \begin{cppcode*}{} export module math; export import :structs; @@ -283,7 +283,7 @@ \end{column} \begin{column}{.5\textwidth} \begin{exampleblock}{Module interface partition} - \begin{cppcode*}{gobble=6} + \begin{cppcode*}{} export module math:structs; @@ -293,7 +293,7 @@ \end{column} \end{columns} \begin{exampleblock}{Implementation} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} module math; import ; @@ -309,7 +309,7 @@ We can split a module's \emph{implementation} into multiple files: \end{block} \begin{exampleblock}{Interface} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} export module math; import :foo; // no export import :bar; // no export @@ -324,7 +324,7 @@ \begin{columns}[t] \begin{column}{.45\textwidth} \begin{exampleblock}{Implementation unit foo} - \begin{cppcode*}{gobble=6} + \begin{cppcode*}{} module math:foo; S f() { ... } @@ -333,7 +333,7 @@ \end{column} \begin{column}{.45\textwidth} \begin{exampleblock}{Implementation unit bar} - \begin{cppcode*}{gobble=6} + \begin{cppcode*}{} module math:bar; std::string b() { ... } @@ -355,7 +355,7 @@ \end{itemize} \item Use \cppinline|import std.compat;| for the entire C and C++ standard library \item No macros are exported. For these, you still need to include the corresponding headers. - \begin{cppcode*}{gobble=4} + \begin{cppcode*}{} import std; // everything C++ #include // for assert() #include // for e.g. CHAR_BIT @@ -427,26 +427,26 @@ \begin{columns} \begin{column}{.35\textwidth} \begin{block}{h.hpp} - \begin{cppcode*}{gobble=6,linenos=false} + \begin{cppcode*}{linenos=false} #include ... \end{cppcode*} \end{block} \begin{block}{a.cpp} - \begin{cppcode*}{gobble=6,linenos=false} + \begin{cppcode*}{linenos=false} #include "h.hpp" ... \end{cppcode*} \end{block} \begin{block}{b.cpp} - \begin{cppcode*}{gobble=6,linenos=false} + \begin{cppcode*}{linenos=false} #include #include "h.hpp" ... \end{cppcode*} \end{block} \begin{block}{c.cpp} - \begin{cppcode*}{gobble=6,linenos=false} + \begin{cppcode*}{linenos=false} #include ... \end{cppcode*} @@ -498,27 +498,27 @@ \begin{column}{.35\textwidth} \small \begin{block}{h.cpp} - \begin{cppcode*}{gobble=6,linenos=false} + \begin{cppcode*}{linenos=false} export module foo; import ; ... \end{cppcode*} \end{block} \begin{block}{a.cpp} - \begin{cppcode*}{gobble=6,linenos=false} + \begin{cppcode*}{linenos=false} import foo; ... \end{cppcode*} \end{block} \begin{block}{b.cpp} - \begin{cppcode*}{gobble=6,linenos=false} + \begin{cppcode*}{linenos=false} import ; import foo; ... \end{cppcode*} \end{block} \begin{block}{c.cpp} - \begin{cppcode*}{gobble=6,linenos=false} + \begin{cppcode*}{linenos=false} #include ... \end{cppcode*} diff --git a/talk/expert/perfectforwarding.tex b/talk/expert/perfectforwarding.tex index a28908b7..3cf1db3d 100644 --- a/talk/expert/perfectforwarding.tex +++ b/talk/expert/perfectforwarding.tex @@ -180,7 +180,7 @@ \begin{frame}[fragile] \frametitlecpp[20]{Forwarding references} \begin{alertblock}{Careful!} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} template struct S { S(T&& t) { ... } // rvalue references void f(T&& t) { ... } // NOT forwarding references @@ -191,7 +191,7 @@ \begin{overprint} \onslide<1> \begin{exampleblock}{Half-way correct version} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} template struct S { template @@ -204,7 +204,7 @@ \end{exampleblock} \onslide<2> \begin{exampleblock}{Correct version} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} template struct S { template , T>, int> = 0> diff --git a/talk/expert/sfinae.tex b/talk/expert/sfinae.tex index 4fd3c2ee..dc637dfc 100644 --- a/talk/expert/sfinae.tex +++ b/talk/expert/sfinae.tex @@ -159,7 +159,7 @@ \end{itemize} \end{block} \begin{block}{Implementation in header type\_traits} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} template using void_t = void; \end{cppcode*} @@ -284,7 +284,7 @@ \begin{frame}[fragile] \frametitlecpp[14]{Back to variadic class templates} \begin{block}{The tuple get function} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} template std::enable_if_t>::type&> @@ -304,7 +304,7 @@ \begin{frame}[fragile] \frametitlecpp[17]{with if constexpr and return type deduction} \begin{block}{The tuple get function} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} template auto& get(tuple& t) { if constexpr(I == 0) diff --git a/talk/morelanguage/exceptions.tex b/talk/morelanguage/exceptions.tex index 33771089..6a608db5 100644 --- a/talk/morelanguage/exceptions.tex +++ b/talk/morelanguage/exceptions.tex @@ -21,7 +21,7 @@ \end{itemize} \end{block} \begin{multicols}{2} - \begin{cppcode*}{fontsize=\small,gobble=2} + \begin{cppcode*}{fontsize=\small} try { process_data(f); } catch (const @@ -30,7 +30,7 @@ } \end{cppcode*} \columnbreak - \begin{cppcode*}{fontsize=\small,firstnumber=7,gobble=2} + \begin{cppcode*}{fontsize=\small,firstnumber=7} void process_data(file &f) { ... if (i >= buffer.size()) @@ -172,7 +172,7 @@ \end{itemize} \end{block} \begin{multicols}{2} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} class C { ... }; void f() { C c1; @@ -185,7 +185,7 @@ } \end{cppcode*} \columnbreak - \begin{cppcode*}{gobble=2,firstnumber=11} + \begin{cppcode*}{firstnumber=11} int main() { try { C c4; @@ -233,7 +233,7 @@ \end{itemize} \end{block} \begin{multicols}{2} - \begin{cppcode*}{fontsize=\scriptsize,gobble=2} + \begin{cppcode*}{fontsize=\scriptsize} try { for (File const &f : files) { try { @@ -248,7 +248,7 @@ } \end{cppcode*} \columnbreak - \begin{cppcode*}{fontsize=\scriptsize,gobble=2} + \begin{cppcode*}{fontsize=\scriptsize} void process_file(File const & file) { ... if (handle = open_file(file)) @@ -278,7 +278,7 @@ \begin{multicols}{2} \begin{minipage}{5cm} \begin{alertblock}{Avoid} - \begin{cppcode*}{fontsize=\scriptsize,gobble=6,linenos=false} + \begin{cppcode*}{fontsize=\scriptsize,linenos=false} for (string const &num: nums) { try { int i = convert(num); // can @@ -294,7 +294,7 @@ \columnbreak \begin{minipage}{5cm} \begin{exampleblock}{Prefer} - \begin{cppcode*}{fontsize=\scriptsize,gobble=6,linenos=false} + \begin{cppcode*}{fontsize=\scriptsize,linenos=false} for (string const &num: nums) { optional i = convert(num); if (i) { @@ -314,7 +314,7 @@ \begin{block}{\texttt{noexcept}} \begin{itemize} \item a function with the \cppinline{noexcept} specifier states that it guarantees to not throw an exception - \begin{cppcode*}{gobble=2,linenos=false} + \begin{cppcode*}{linenos=false} int f() noexcept; \end{cppcode*} \begin{itemize} @@ -323,7 +323,7 @@ \item allows the compiler to optimize around that knowledge \end{itemize} \item a function with \cppinline{noexcept(expression)} is only \cppinline{noexcept} when \cppinline{expression} evaluates to \cppinline{true} at compile-time - \begin{cppcode*}{gobble=2,linenos=false} + \begin{cppcode*}{linenos=false} int safe_if_8B() noexcept(sizeof(long)==8); \end{cppcode*} \end{itemize} @@ -346,13 +346,13 @@ \end{itemize} \end{block} \begin{block}{} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} constexpr bool callCannotThrow = noexcept(f()); if constexpr (callCannotThrow) { ... } \end{cppcode*} \end{block} \begin{block}{} - \begin{cppcode*}{gobble=2,firstnumber=3} + \begin{cppcode*}{firstnumber=3} template void g(Function f) noexcept(noexcept(f())) { ... diff --git a/talk/morelanguage/lambda.tex b/talk/morelanguage/lambda.tex index ee7cee72..c9e7309c 100644 --- a/talk/morelanguage/lambda.tex +++ b/talk/morelanguage/lambda.tex @@ -35,7 +35,7 @@ \end{itemize} \end{block} \begin{exampleblock}{Usage example} - \begin{cppcode*}{firstnumber=4,gobble=2} + \begin{cppcode*}{firstnumber=4} int data[]{1,2,3,4,5}; auto f = [](int i) { std::cout << i << " squared is " << i*i << '\n'; @@ -59,7 +59,7 @@ \begin{itemize} \item Only way to specify return type for lambdas \item Allows to simplify inner type definition - \begin{cppcode*}{gobble=4} + \begin{cppcode*}{} class Equation { using ResultType = double; ResultType evaluate(); @@ -90,7 +90,7 @@ \end{block} \pause \begin{alertblock}{Error} - \begin{minted}[gobble=6]{text} + \begin{minted}{text} error: 'increment' is not captured [](int x) { return x+increment; }); ^ @@ -132,7 +132,7 @@ \end{exampleblock} \pause \begin{alertblock}{Error} - \begin{minted}[gobble=4]{text} + \begin{minted}{text} error: assignment of read-only variable 'sum' [sum](int x) { sum += x; }); \end{minted} @@ -178,7 +178,7 @@ \begin{columns} \scriptsize \begin{column}{.25\textwidth} - \begin{cppcode*}{gobble=6} + \begin{cppcode*}{} int sum = 0, off = 1; auto l = [&sum, off] @@ -194,7 +194,7 @@ \end{cppcode*} \end{column} \begin{column}{.45\textwidth} - \begin{cppcode*}{gobble=6, firstnumber=13} + \begin{cppcode*}{firstnumber=13} int sum = 0, off = 1; struct __lambda4 { int& sum; int off; @@ -249,7 +249,7 @@ Inside a (non-static) member function, we can capture \cppinline{this}. \end{block} \begin{block}{} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} [ this](...) { use(*this); }; [ &](...) { use(*this); }; [&, this](...) { use(*this); }; @@ -260,7 +260,7 @@ \end{block} \pause \begin{block}{} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} [ *this](...) { use(*this); }; // C++17 [&, *this](...) { use(*this); }; // C++17 [=, *this](...) { use(*this); }; // C++17 @@ -275,11 +275,11 @@ \begin{block}{Generic lambdas (aka.\ polymorphic lambdas)} \begin{itemize} \item The type of lambda parameters may be \cppinline{auto}. - \begin{cppcode*}{linenos=false,gobble=4} + \begin{cppcode*}{linenos=false} auto add = [](auto a, auto b) { return a + b; }; \end{cppcode*} \item The generated \cppinline{operator()} becomes a template function: - \begin{cppcode*}{linenos=false,gobble=4} + \begin{cppcode*}{linenos=false} template auto operator()(T a, U b) const { return a + b; } \end{cppcode*} @@ -287,10 +287,10 @@ \end{itemize} \end{block} \begin{block}{Explicit template parameters (\cpp20)} - \begin{cppcode*}{linenos=false,gobble=4} - auto add = [](T a, T b) - { return a + b; }; - \end{cppcode*} + \begin{cppcode*}{linenos=false} + auto add = [](T a, T b) + { return a + b; }; + \end{cppcode*} \begin{itemize} \item The types of \cppinline{a} and \cppinline{b} must be the same. \end{itemize} @@ -331,7 +331,7 @@ \end{block} \begin{exampleblockGB}{Example}{https://godbolt.org/z/GoE6xM8EG}{\texttt{lambda \cpp20}} \small - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} struct S { decltype([](int i) { std::cout << i; }) f; } s; diff --git a/talk/morelanguage/morestl.tex b/talk/morelanguage/morestl.tex index 4ead2b2b..1c808a8f 100644 --- a/talk/morelanguage/morestl.tex +++ b/talk/morelanguage/morestl.tex @@ -217,7 +217,7 @@ \end{block} \begin{exampleblockGB}{Practically}{https://godbolt.org/z/bxzEsM3de}{\texttt{variant visitor}} \small - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} struct Visitor { auto operator()(int i) {return "i:"+std::to_string(i);} auto operator()(float f) {return "f:"+std::to_string(f);} @@ -242,7 +242,7 @@ \end{block} \begin{exampleblockGB}{Practically}{https://godbolt.org/z/WcdnT1hra}{\texttt{variant $\lambda$ visitor}} \small - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} template // covered in expert part struct Overload : Ts ... { using Ts::operator()...; }; template @@ -412,7 +412,7 @@ \end{block} \begin{exampleblock}{} \small - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} class C { ... }; // complex, cannot change template <> struct std::tuple_size { @@ -459,7 +459,7 @@ \frametitlecpp[11]{Practical usage / timing some \cpp code} \begin{exampleblockGB}{How to measure the time spent in some code}{https://godbolt.org/z/PzKWer5eb}{\texttt{timing}} \small - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} #include std::chrono::high_resolution_clock clock; diff --git a/talk/morelanguage/move.tex b/talk/morelanguage/move.tex index 85da62e0..038c7baa 100644 --- a/talk/morelanguage/move.tex +++ b/talk/morelanguage/move.tex @@ -47,7 +47,7 @@ \begin{exampleblock}{Another potentially inefficient code} \begin{overprint} \onslide<1-2> - \begin{cppcode*}{gobble=4} + \begin{cppcode*}{} T consumeVector(std::vector input) { // ... change elements, compute result return result; @@ -57,7 +57,7 @@ consumeVector(values); // being copied now \end{cppcode*} \onslide<3-4> - \begin{cppcode*}{gobble=4} + \begin{cppcode*}{} T consumeVector(std::vector const & input) { std::vector tmp{input}; // ... change elements, compute result @@ -67,7 +67,7 @@ consumeVector(values); // maybe copied internally? \end{cppcode*} \onslide<5-> - \begin{cppcode*}{gobble=4} + \begin{cppcode*}{} T consumeVector(std::vector & input) { // ... change elements, compute result return result; @@ -223,7 +223,7 @@ \frametitlecpp[11]{Move semantics: recommended implementation} \begin{exampleblock}{Practically} \small - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} class Movable { Movable(); Movable(const Movable &other); @@ -248,7 +248,7 @@ \frametitlecpp[11]{Move semantics: alternative implementation} \begin{exampleblock}{Practically} \small - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} class Movable { Movable(); Movable(const Movable &other); diff --git a/talk/morelanguage/raii.tex b/talk/morelanguage/raii.tex index b3cebfca..710a6be2 100644 --- a/talk/morelanguage/raii.tex +++ b/talk/morelanguage/raii.tex @@ -84,7 +84,7 @@ \frametitlecpp[98]{RAII in practice} \begin{exampleblock}{An RAII File class} \small - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} class File { public: // constructor: acquire resource @@ -337,7 +337,7 @@ \frametitlecpp[11]{Quiz: \texttt{std::shared\_ptr} in use} \begin{exampleblockGB}{What is the output of this code?}{https://godbolt.org/z/vM35Y6qEW}{\texttt{shared\_ptr} quiz} \small - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} auto shared = std::make_shared(100); auto print = [shared](){ std::cout << "Use: " << shared.use_count() << " " @@ -355,7 +355,7 @@ \pause \begin{block}{} \small - \begin{minted}[autogobble=true]{bash} + \begin{minted}{bash} Use: 2 value: 100 Use: 3 value: 101 Use: 2 value: 101 @@ -385,7 +385,7 @@ \end{exampleblock} \begin{block}{} \small - \begin{minted}[autogobble=true]{bash} + \begin{minted}{bash} Use: 1 value: 100 Use: 2 value: 101 Use: 1 value: 101 @@ -399,7 +399,7 @@ \frametitlecpp[11]{Quiz: \texttt{shared\_ptr} and \texttt{weak\_ptr} in use} \begin{exampleblockGB}{What is the output of this code?}{https://godbolt.org}{\texttt{shared/weak\_ptr}} \small - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} auto shared = std::make_shared(100); std::weak_ptr weak{ shared }; print(); // with print as before @@ -415,7 +415,7 @@ \pause \begin{block}{} \small - \begin{minted}[autogobble=true]{bash} + \begin{minted}{bash} Use: 1 value: 100 Use: 2 value: 101 Use: 1 value: 101 @@ -457,7 +457,7 @@ \item compile and run the program. It doesn't generate any output. \item Run with valgrind if possible to check for leaks { \scriptsize - \begin{minted}[gobble=6]{shell-session} + \begin{minted}{shell-session} $ valgrind --leak-check=full --track-origins=yes ./smartPointers \end{minted} } diff --git a/talk/morelanguage/random.tex b/talk/morelanguage/random.tex index 64475f43..71fd7787 100644 --- a/talk/morelanguage/random.tex +++ b/talk/morelanguage/random.tex @@ -85,7 +85,7 @@ \end{itemize} \end{block} \begin{exampleblock}{Distributions sharing a non-deterministic engine} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} std::random_device rd; std::default_random_engine engine{rd()}; std::uniform_int_distribution dist(2,7);//min,max diff --git a/talk/morelanguage/ranges.tex b/talk/morelanguage/ranges.tex index f8e6d71d..8d3672a0 100644 --- a/talk/morelanguage/ranges.tex +++ b/talk/morelanguage/ranges.tex @@ -32,7 +32,7 @@ \end{block} \begin{exampleblockGB}{Example}{https://godbolt.org/z/d1vTv4TMa}{Views} { \small - \begin{cppcode*}{gobble=4} + \begin{cppcode*}{} auto const numbers = std::views::iota(0, 6); auto even = [](int i) { return 0 == i % 2; }; auto square = [](int i) { return i * i; }; @@ -72,7 +72,7 @@ \end{itemize} \end{block} \begin{exampleblockGB}{Example}{https://godbolt.org/z/bWe6W69oE}{Lazy view} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} // print first 20 prime numbers above 1000000 for (int i: std::views::iota(1000000) | std::views::filter(odd) diff --git a/talk/morelanguage/stl.tex b/talk/morelanguage/stl.tex index 145ce0c7..fb1b3ccc 100644 --- a/talk/morelanguage/stl.tex +++ b/talk/morelanguage/stl.tex @@ -26,7 +26,7 @@ \begin{frame}[fragile] \frametitlecpp[14]{STL in practice} \begin{exampleblockGB}{STL example}{https://godbolt.org/z/n8ahEr5f6}{STL} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} #include #include #include // `import std;` in C++23 @@ -127,7 +127,7 @@ \begin{block}{} Conceptually a container of \cppinline{std::pair} \end{block} - \begin{cppcode*}{gobble=4} + \begin{cppcode*}{} #include std::unordered_map m; m["hello"] = 1; // inserts new key, def. constr. value @@ -154,7 +154,7 @@ \item Can be customized for your types via template specialization \end{itemize} \end{block} - \begin{cppcode*}{gobble=4} + \begin{cppcode*}{} #include std::hash h; std::cout << h("hello"); // 2762169579135187400 diff --git a/talk/morelanguage/templates.tex b/talk/morelanguage/templates.tex index de87399e..e212564b 100644 --- a/talk/morelanguage/templates.tex +++ b/talk/morelanguage/templates.tex @@ -43,7 +43,7 @@ \begin{lrbox}{\codepiece} \begin{minipage}{.35\linewidth} \small - \begin{cppcode*}{gobble=4} + \begin{cppcode*}{} template T func(T a) { return a; @@ -55,7 +55,7 @@ \begin{lrbox}{\codepiecea} \begin{minipage}{.4\linewidth} \small - \begin{cppcode*}{gobble=4,linenos=false} + \begin{cppcode*}{linenos=false} int func(int a) { return a; } @@ -66,7 +66,7 @@ \begin{lrbox}{\codepieceb} \begin{minipage}{.4\linewidth} \small - \begin{cppcode*}{gobble=4,linenos=false} + \begin{cppcode*}{linenos=false} double func(double a) { return a; } @@ -159,7 +159,7 @@ \frametitlecpp[98]{Nested templates} \begin{exampleblockGB}{Nested templates}{https://godbolt.org/z/a9nPnK9jx}{Nested templates} \small - \begin{cppcode*}{gobble=8} + \begin{cppcode*}{} template struct Map { template @@ -282,7 +282,7 @@ \onslide<1> \begin{alertblock}{} \footnotesize - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} template void f(typename C::value_type v) { ... } f(std::vector{...}); // cannot deduce C @@ -300,7 +300,7 @@ \onslide<2> \begin{alertblock}{} \footnotesize - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} template void reduce(const C& cont, const F& f = std::plus{}); reduce(std::vector{...}); // error: cannot deduce F @@ -451,14 +451,14 @@ \end{cppcode} \begin{overprint}[\columnwidth] \onslide<1> - \begin{cppcode*}{gobble=2,firstnumber=6} + \begin{cppcode*}{firstnumber=6} Pair p{42, "hello"}; // Pair \end{cppcode*} \onslide<2> - \begin{cppcode*}{gobble=2,firstnumber=6} + \begin{cppcode*}{firstnumber=6} template Pair(A, const char*) -> Pair; @@ -470,7 +470,7 @@ \begin{frame}[fragile] \frametitlecpp[17]{Class Template Argument Deduction (CTAD)} \begin{block}{Standard library examples} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} std::pair p{1.2, true}; // std::pair std::tuple t{1.2, true, 32}; // std::tuple diff --git a/talk/objectorientation/adl.tex b/talk/objectorientation/adl.tex index 08c430f4..7c12eda0 100644 --- a/talk/objectorientation/adl.tex +++ b/talk/objectorientation/adl.tex @@ -60,7 +60,7 @@ \begin{column}{.35\textwidth} Don't write : \vspace{-1mm} - \begin{cppcode*}{gobble=6} + \begin{cppcode*}{} namespace MyNS { struct A { T func(...); @@ -71,7 +71,7 @@ \begin{column}{.35\textwidth} Prefer : \vspace{-1mm} - \begin{cppcode*}{gobble=6,firstnumber=6} + \begin{cppcode*}{firstnumber=6} namespace MyNS { struct A { ... }; T func(const A&, ..); @@ -99,14 +99,14 @@ \begin{columns}[t] \begin{column}{.35\textwidth} Don't write : - \begin{cppcode*}{gobble=6} + \begin{cppcode*}{} N::A a,b; std::swap(a, b); \end{cppcode*} \end{column} \begin{column}{.35\textwidth} Prefer : - \begin{cppcode*}{gobble=6,firstnumber=3} + \begin{cppcode*}{firstnumber=3} N::A a,b; using std::swap; swap(a, b); @@ -121,7 +121,7 @@ \end{itemize} \begin{columns} \begin{column}{.7\textwidth} - \begin{cppcode*}{gobble = 6,firstnumber=6} + \begin{cppcode*}{firstnumber=6} namespace N { class A { ... }; // optimized swap for A @@ -146,7 +146,7 @@ \end{block} \begin{exampleblock}{\texttt{operator<<} as hidden friend} \small - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} class Complex { float m_real, m_imag; public: @@ -175,7 +175,7 @@ \footnotesize \begin{overprint} \onslide<1> - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} std::ostream & operator<< // out-of-class definition (std::ostream & os, Complex const & c) { ... } struct Fraction { @@ -188,7 +188,7 @@ \end{cppcode*} \onslide<2> - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} std::ostream & operator<< // out-of-class definition (std::ostream & os, Complex const & c) { ... } struct Fraction { diff --git a/talk/objectorientation/advancedoo.tex b/talk/objectorientation/advancedoo.tex index b74d3a1d..a887ca58 100644 --- a/talk/objectorientation/advancedoo.tex +++ b/talk/objectorientation/advancedoo.tex @@ -48,7 +48,7 @@ \end{itemize} \end{block} \begin{multicols}{2} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} Polygon p; int f(Drawable & d) {...} @@ -99,7 +99,7 @@ \end{itemize} \end{block} \begin{multicols}{2} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} Polygon p; int f(Drawable & d) {...} @@ -132,7 +132,7 @@ \end{itemize} \end{block} \begin{multicols}{2} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} Polygon p; p.draw(); // ? @@ -168,7 +168,7 @@ \begin{overprint} \onslide<2> \begin{multicols}{2} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} Polygon p; p.draw(); // Polygon.draw @@ -192,7 +192,7 @@ \onslide<3> \begin{multicols}{2} - \begin{cppcode*}{gobble=2,highlightlines=5} + \begin{cppcode*}{highlightlines=5} Polygon p; p.draw(); // Polygon.draw @@ -317,7 +317,7 @@ \end{block} \pause \begin{multicols}{2} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} // Error : abstract class Shape s; @@ -415,7 +415,7 @@ \end{itemize} \end{block} \begin{multicols}{2} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} struct Drawable { virtual ~Drawable() = default; @@ -440,7 +440,7 @@ \item unless you inherit them using \cppinline{using} \end{itemize} \end{block} - \begin{cppcode*}{gobble=0} + \begin{cppcode*}{} struct BaseClass { virtual int foo(std::string); virtual int foo(int); @@ -488,7 +488,7 @@ \end{tikzpicture} \columnbreak \vspace{2cm} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} class TextBox : public Rectangle, Text { // inherits from both diff --git a/talk/objectorientation/constructors.tex b/talk/objectorientation/constructors.tex index f9c994c4..6e210f63 100644 --- a/talk/objectorientation/constructors.tex +++ b/talk/objectorientation/constructors.tex @@ -11,7 +11,7 @@ \end{itemize} \end{block} \begin{multicols}{2} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} class C { public: C(); @@ -23,7 +23,7 @@ }; \end{cppcode*} \columnbreak - \begin{cppcode*}{gobble=2,firstnumber=10} + \begin{cppcode*}{firstnumber=10} // note: special notation for // initialization of members C::C() : a(0) {} @@ -264,7 +264,7 @@ \begin{frame}[fragile] \frametitlecpp[11]{Calling constructors} \begin{block}{After object declaration, arguments within \{\}} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} struct A { int a; float b; @@ -285,7 +285,7 @@ \begin{frame}[fragile] \frametitlecpp[98]{Calling constructors the old way} \begin{block}{Arguments are given within (), aka \cpp98 nightmare} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} struct A { int a; float b; diff --git a/talk/objectorientation/inheritance.tex b/talk/objectorientation/inheritance.tex index 0d0a0f7b..086909d5 100644 --- a/talk/objectorientation/inheritance.tex +++ b/talk/objectorientation/inheritance.tex @@ -3,7 +3,7 @@ \begin{frame}[fragile] \frametitlecpp[98]{First inheritance} \begin{multicols}{2} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} struct MyFirstClass { int a; void squareA() { a *= a; } @@ -61,7 +61,7 @@ \end{itemize} \end{block} \begin{multicols}{2} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} class MyFirstClass { public: void setA(int x); @@ -72,7 +72,7 @@ }; \end{cppcode*} \columnbreak - \begin{cppcode*}{gobble=2,firstnumber=9} + \begin{cppcode*}{firstnumber=9} MyFirstClass obj; obj.a = 5; // error ! obj.setA(5); // ok @@ -92,7 +92,7 @@ Gives access to classes inheriting from base class \end{block} \begin{multicols}{2} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} class MyFirstClass { public: void setA(int a); @@ -103,7 +103,7 @@ }; \end{cppcode*} \columnbreak - \begin{cppcode*}{gobble=2,firstnumber=13} + \begin{cppcode*}{firstnumber=13} class MySecondClass : public MyFirstClass { public: @@ -164,7 +164,7 @@ \draw[very thick,-Triangle] (MyThirdClass)--(MySecondClass) node[midway,right] {public}; \end{tikzpicture} \columnbreak - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} void funcSecond() { int a = priv; // Error int b = prot; // OK @@ -206,7 +206,7 @@ \draw[very thick,-Triangle] (MyThirdClass)--(MySecondClass) node[midway,right] {public}; \end{tikzpicture} \columnbreak - \begin{cppcode*}{gobble=2,highlightlines=14} + \begin{cppcode*}{highlightlines=14} void funcSecond() { int a = priv; // Error int b = prot; // OK @@ -248,7 +248,7 @@ \draw[very thick,-Triangle] (MyThirdClass)--(MySecondClass) node[midway,right] {public}; \end{tikzpicture} \columnbreak - \begin{cppcode*}{gobble=2,highlightlines=8-9} + \begin{cppcode*}{highlightlines=8-9} void funcSecond() { int a = priv; // Error int b = prot; // OK diff --git a/talk/objectorientation/objectsclasses.tex b/talk/objectorientation/objectsclasses.tex index fc5e69c0..5ab314d7 100644 --- a/talk/objectorientation/objectsclasses.tex +++ b/talk/objectorientation/objectsclasses.tex @@ -32,7 +32,7 @@ \begin{frame}[fragile] \frametitlecpp[98]{My first class} \begin{multicols}{2} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} struct MyFirstClass { int a; void squareA() { @@ -68,7 +68,7 @@ \begin{columns}[t] \begin{column}{.45\textwidth} \begin{block}{Header: MyClass.hpp} - \begin{cppcode*}{gobble=4} + \begin{cppcode*}{} #pragma once struct MyClass { int a; @@ -77,7 +77,7 @@ \end{cppcode*} \end{block} \begin{block}{Implementation: MyClass.cpp} - \begin{cppcode*}{gobble=4} + \begin{cppcode*}{} #include "MyClass.hpp" void MyClass::squareA() { a *= a; @@ -87,7 +87,7 @@ \end{column} \begin{column}{.45\textwidth} \begin{block}{User 1: main.cpp} - \begin{cppcode*}{gobble=4} + \begin{cppcode*}{} #include "MyClass.hpp" int main() { MyClass mc; @@ -96,7 +96,7 @@ \end{cppcode*} \end{block} \begin{block}{User 2: fun.cpp} - \begin{cppcode*}{gobble=4} + \begin{cppcode*}{} #include "MyClass.hpp" void f(MyClass& mc) { mc.squareA(); diff --git a/talk/objectorientation/operators.tex b/talk/objectorientation/operators.tex index d5d83477..94d11b98 100644 --- a/talk/objectorientation/operators.tex +++ b/talk/objectorientation/operators.tex @@ -107,7 +107,7 @@ \end{block} \begin{exampleblock}{\texttt{operator+} as a friend} \footnotesize - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} class Complex { float m_r, m_i; friend Complex operator+(Complex const & a, Complex const & b); diff --git a/talk/objectorientation/typecasting.tex b/talk/objectorientation/typecasting.tex index 5b45887f..924dba0e 100644 --- a/talk/objectorientation/typecasting.tex +++ b/talk/objectorientation/typecasting.tex @@ -24,7 +24,7 @@ \frametitlecpp[98]{Type casting example} \small \begin{exampleblockGB}{Practically}{https://godbolt.org/z/16faqc64s}{\texttt{casting}} - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} struct A{ virtual ~A()=default; } a; struct B : A {} b; @@ -67,7 +67,7 @@ \end{block} \begin{alertblock}{Casts to avoid} \scriptsize - \begin{cppcode*}{gobble=2} + \begin{cppcode*}{} void func(A const & a) { A& ra = a; // Error: not const A& ra = const_cast(a); // Compiles. Bad design! diff --git a/talk/python/ctypes.tex b/talk/python/ctypes.tex index bc81e4e6..296f956b 100644 --- a/talk/python/ctypes.tex +++ b/talk/python/ctypes.tex @@ -28,7 +28,7 @@ \end{cppcode*} \end{block} \begin{exampleblock}{calling the mandel library} - \begin{minted}[gobble=4]{python} + \begin{minted}{python} from ctypes import * libmandel = CDLL('libmandelc.so') v = libmandel.mandel(c_float(0.3), c_float(1.2)) diff --git a/talk/python/marryingcandcpp.tex b/talk/python/marryingcandcpp.tex index 16dec9b6..c27bf7a1 100644 --- a/talk/python/marryingcandcpp.tex +++ b/talk/python/marryingcandcpp.tex @@ -25,7 +25,7 @@ \end{cppcode*} \end{exampleblock} \begin{block}{Binary symbols : file.o} - \begin{minted}[gobble=4]{shell} + \begin{minted}{shell} # nm file.o 000000000000001a T square 0000000000000000 T sum @@ -44,7 +44,7 @@ \end{cppcode*} \end{exampleblock} \begin{block}{Binary symbols : file.o} - \begin{minted}[gobble=4]{shell} + \begin{minted}{shell} # nm file.o 0000000000000000 T _Z3sumff 000000000000002a T _Z6squaref @@ -57,7 +57,7 @@ \frametitle{Forcing C mangling in \cpp} \begin{block}{extern ``C''} These functions will use C mangling : - \begin{cppcode*}{gobble=1} + \begin{cppcode*}{} extern "C" { float sum(float a, float b); int square(int a); diff --git a/talk/python/modulewriting.tex b/talk/python/modulewriting.tex index b3095d00..1b78fcd8 100644 --- a/talk/python/modulewriting.tex +++ b/talk/python/modulewriting.tex @@ -61,7 +61,7 @@ \end{itemize} \end{block} \begin{block}{mandel.py - see exercises/python exercise} - \begin{minted}[gobble=4]{python} + \begin{minted}{python} from mandel import mandel v = mandel(0.7, 1.2) \end{minted} diff --git a/talk/setup.tex b/talk/setup.tex index 9f246154..3e1e918c 100644 --- a/talk/setup.tex +++ b/talk/setup.tex @@ -50,11 +50,11 @@ \usepackage[utf8]{inputenc} \usepackage{newunicodechar} \usepackage{minted} -\newminted{tex}{linenos} -\newminted{cpp}{gobble=4,linenos} -\newminted{shell-session}{gobble=4} -\newminted[makefile]{shell-session}{gobble=4} -\newminted{python}{linenos=true,gobble=4} +\newminted{tex}{linenos,gobble=4} +\newminted{cpp}{autogobble,linenos} +\newminted{shell-session}{autogobble} +\newminted[makefile]{shell-session}{autogobble} +\newminted{python}{linenos=true,autogobble} \newmintinline[cppinline]{cpp}{} \usepackage{fancyvrb} diff --git a/talk/tools/doxygen.tex b/talk/tools/doxygen.tex index 4bd7d665..583ee3cb 100644 --- a/talk/tools/doxygen.tex +++ b/talk/tools/doxygen.tex @@ -24,7 +24,7 @@ \begin{block}{Comment blocks} \begin{columns} \begin{column}{.35\textwidth} - \begin{cppcode*}{gobble=6} + \begin{cppcode*}{} /** * text/directives ... */ @@ -37,7 +37,7 @@ \end{cppcode*} \end{column} \begin{column}{.35\textwidth} - \begin{cppcode*}{gobble=6,firstnumber=10} + \begin{cppcode*}{firstnumber=10} /// /// text/directives ... /// diff --git a/talk/tools/sanitizers.tex b/talk/tools/sanitizers.tex index 3948b081..284803be 100644 --- a/talk/tools/sanitizers.tex +++ b/talk/tools/sanitizers.tex @@ -39,12 +39,12 @@ \begin{overprint} \onslide<1> \vfill - \begin{cppcode*}{gobble=4} + \begin{cppcode*}{} int i = *address; \end{cppcode*} \onslide<2-> \vfill - \begin{cppcode*}{gobble=4} + \begin{cppcode*}{} if (IsPoisoned(address)) { ReportError(address, kAccessSize, kIsWrite); } @@ -67,7 +67,7 @@ \begin{multicols}{2} \begin{overprint} \onslide<1> - \begin{cppcode*}{gobble=4} + \begin{cppcode*}{} void foo() { char a[8]; char b[8]; diff --git a/talk/tools/vcs.tex b/talk/tools/vcs.tex index d0ea6eb3..95e7688b 100644 --- a/talk/tools/vcs.tex +++ b/talk/tools/vcs.tex @@ -28,7 +28,7 @@ \begin{frame}[fragile] \frametitle{Git crash course} - \begin{minted}[gobble=4]{shell-session} + \begin{minted}{shell-session} $ git init myProject Initialized empty Git repository in myProject/.git/ From 86a5878ab2f87b6cf520bf47cbabaaa6c581db86 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 3 Feb 2025 23:11:52 +0000 Subject: [PATCH 130/156] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/codespell-project/codespell: v2.3.0 → v2.4.1](https://github.com/codespell-project/codespell/compare/v2.3.0...v2.4.1) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6ee123be..20be3b7a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/codespell-project/codespell - rev: 'v2.3.0' + rev: 'v2.4.1' hooks: - id: codespell args: ["-I", "codespell.txt"] From 66c92b7ff7466f67838757591faf27cf73965b9c Mon Sep 17 00:00:00 2001 From: David Chamont Date: Thu, 13 Feb 2025 15:46:55 +0100 Subject: [PATCH 131/156] Review operators exercise and split a preceding classes exercise from it. --- exercises/ExerciseSchedule_EssentialCourse.md | 4 +- exercises/ExercisesCheatSheet.md | 47 ++++-- exercises/classes/.gitignore | 1 + exercises/classes/CMakeLists.txt | 13 ++ exercises/classes/Makefile | 11 ++ exercises/classes/README.md | 33 ++++ exercises/classes/classes.cpp | 75 +++++++++ exercises/classes/classes_sol | Bin 0 -> 97176 bytes exercises/classes/solution/classes_sol.cpp | 95 +++++++++++ exercises/operators/.gitignore | 2 + exercises/operators/CMakeLists.txt | 5 +- exercises/operators/Makefile | 10 +- exercises/operators/README.md | 27 ++- exercises/operators/operators.cpp | 158 ++++++++++-------- .../operators/solution/operators.sol.cpp | 126 -------------- .../operators/solution/operators_sol.cpp | 135 +++++++++++++++ 16 files changed, 516 insertions(+), 226 deletions(-) create mode 100644 exercises/classes/.gitignore create mode 100644 exercises/classes/CMakeLists.txt create mode 100644 exercises/classes/Makefile create mode 100644 exercises/classes/README.md create mode 100644 exercises/classes/classes.cpp create mode 100755 exercises/classes/classes_sol create mode 100644 exercises/classes/solution/classes_sol.cpp create mode 100644 exercises/operators/.gitignore delete mode 100644 exercises/operators/solution/operators.sol.cpp create mode 100644 exercises/operators/solution/operators_sol.cpp diff --git a/exercises/ExerciseSchedule_EssentialCourse.md b/exercises/ExerciseSchedule_EssentialCourse.md index ab2899fd..4eed3641 100644 --- a/exercises/ExerciseSchedule_EssentialCourse.md +++ b/exercises/ExerciseSchedule_EssentialCourse.md @@ -37,10 +37,12 @@ People should replay them and discover the tools by themselves. Day 2 - OO Exercises -------------------- -### Polymorphism (directory: [`polymorphism`](polymorphism), [CheatSheet](ExercisesCheatSheet.md#polymorphism-directory-polymorphism)) +### My first classes (directory: [`classes`](classes), [CheatSheet](ExercisesCheatSheet.md#classes-directory-classes)) ### Operator overloading (directory: [`operators`](operators), [CheatSheet](ExercisesCheatSheet.md#operator-overloading-directory-operators)) +### Polymorphism (directory: [`polymorphism`](polymorphism), [CheatSheet](ExercisesCheatSheet.md#polymorphism-directory-polymorphism)) + ### Virtual inheritance (directory: [`virtual_inheritance`](virtual_inheritance), [CheatSheet](ExercisesCheatSheet.md#virtual-inheritance-directory-virtual_inheritance)) diff --git a/exercises/ExercisesCheatSheet.md b/exercises/ExercisesCheatSheet.md index 9982dab2..71ec9db8 100644 --- a/exercises/ExercisesCheatSheet.md +++ b/exercises/ExercisesCheatSheet.md @@ -45,6 +45,37 @@ The idea of this exercise is to play with all kinds of possible loops and contro Object-orientation Exercises ---------------------------- +### Classes (directory: [`classes`](classes)) + +This exercise is about doing a basic class, not using any operator overloading. It also paves the way for object-functions, making a first algo-like class. + +You may discuss with the students: +- pros and cons of making the constructor explicit or not, +- pros and cons of having multiply() and equal() either as member functions, + friend free functions or external free functions. +- optionally, thed difference between equality and equivalence. + +NOTE: I did not find a justified need to add operator=... + +### Operator overloading (directory: [`operators`](operators)) + +Here we take the class from the previous exercise, and we try to make +anything an operator that makes sense. + +Tips and tricks: +- When the argument of CHECK() has a comma not between parentheses, for example + curly braces, add an additional global level of parenthesis, or CHECK() will + think it has several arguments. + +You may discuss with the students: +- the chaining of operator<< +- in a set of consistent operators (such as == and !=), + reusing versus performance. +- object-functions. +- for what concerns the related operators, such as * and *=, + the choice to be made consitent reuse or performant + specialization of each operator. + ### Polymorphism (directory: [`polymorphism`](polymorphism)) First create a Pentagon and an Hexagon and call computePerimeter. Can be used to break the ice. @@ -79,22 +110,6 @@ See and solve the compilation issue about missing Drawable constructor. Understa See the new id being printed twice. -### Operator overloading (directory: [`operators`](operators)) - -This exercise is about making `main` run successfully by completing the implementation of `Fraction`. -Implement a constructor for `Fraction` and add two integer data members for numerator and denominator. -Comment out everything in `main` except the first two LOCs. -This should compile now and print nothing. - -Then uncomment the `std::cout` statements and implement `operator<<` for `Fraction`. -Compile and run. - -Proceed this way through the entire exercise. -There are multiple possibilities to implement some operators, e.g. as members, as hidden friends, or as free functions. -Also when and where to normalize a fraction is up to the students. -All solutions are fine, as long as the `main` function runs successfully. - - Modern C++ Exercises -------------------- diff --git a/exercises/classes/.gitignore b/exercises/classes/.gitignore new file mode 100644 index 00000000..8a8577fc --- /dev/null +++ b/exercises/classes/.gitignore @@ -0,0 +1 @@ +classes classes_sol \ No newline at end of file diff --git a/exercises/classes/CMakeLists.txt b/exercises/classes/CMakeLists.txt new file mode 100644 index 00000000..cfc53a9c --- /dev/null +++ b/exercises/classes/CMakeLists.txt @@ -0,0 +1,13 @@ +# Set up the project. +cmake_minimum_required( VERSION 3.12 ) +project( operators LANGUAGES CXX ) + +# Set up the compilation environment. +include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) + +# Create the user's executable. +add_executable( classes "classes.cpp" ) + +# Create the "solution executable". +add_executable( classes_sol EXCLUDE_FROM_ALL "solution/classes_sol.cpp" ) +add_dependencies( solution classes_sol ) diff --git a/exercises/classes/Makefile b/exercises/classes/Makefile new file mode 100644 index 00000000..b0a6014b --- /dev/null +++ b/exercises/classes/Makefile @@ -0,0 +1,11 @@ +all: classes +solution: classes_sol + +clean: + rm -f *o classes *~ classes_sol + +classes : classes.cpp + ${CXX} -g -std=c++17 -O0 -Wall -Wextra -L. -o $@ $< + +classes_sol : solution/classes_sol.cpp + ${CXX} -g -std=c++17 -O0 -Wall -Wextra -L. -o $@ $< diff --git a/exercises/classes/README.md b/exercises/classes/README.md new file mode 100644 index 00000000..881e2963 --- /dev/null +++ b/exercises/classes/README.md @@ -0,0 +1,33 @@ + +## Instructions + +STEP 1 +- Complete the class Fraction so that a Fraction can be construct from one or two integer. + Check the first two lines of main() are working (comment out the rest) +- Add the function equal(). + Check the second section of main() works. +- Add the function multiply(). + Check the whole main() works. + +STEP 2 +- Replace the function printTestResult() by a class TestResultPrinter + with a method process() that take the same arguments as before. + Upgrade CHECK() and main(). +- Transform the WIDTH constant into a variable member of TestResultPrinter, + which is initialized in its constructor. + Upgrade main(). + +OPTIONAL STEP 3 +- Move multiply() and compare() as friend functions within the class Fraction. + Check main() works. +- Remove the accessors numerator() and denominator(). + Check main() works. + +OPTIONAL STEP 4 +- Remove the systematic call to normalize(). +- Add a equivalent() method to Fraction. +- Upgrade the tests accordingly. +- Transform the private normalize() into a public const normalized() method + which return the normalized fraction. +- Add some tests to check normalized(). + diff --git a/exercises/classes/classes.cpp b/exercises/classes/classes.cpp new file mode 100644 index 00000000..dbf7e45e --- /dev/null +++ b/exercises/classes/classes.cpp @@ -0,0 +1,75 @@ +#include +#include +#include + +class Fraction { + +public: + + // ADD YOUR CODE HERE + + std::string str() const { + std::ostringstream oss; + oss << m_num << '/' << m_denom; + return oss.str(); + } + + int numerator() const { + return m_num; + } + int denominator() const { + return m_denom; + } + +private: + + void normalize() { + const int gcd = std::gcd(m_num, m_denom); + m_num /= gcd; + m_denom /= gcd; + } + + int m_num, m_denom; +}; + +// ADD YOUR CODE HERE + +#define CHECK(print,what) print(#what, what) + +unsigned int WIDTH {20}; + +void printTestResult(std::string const & what, bool passed) { + std::cout << std::setw(WIDTH) << what << ": " << (passed ? "PASS" : "** FAIL **") << '\n'; +} + +int main() { + + // create a fraction with values 3 (which is 3/1) and 1/3 + std::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�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 literal 0 HcmV?d00001 diff --git a/exercises/classes/solution/classes_sol.cpp b/exercises/classes/solution/classes_sol.cpp new file mode 100644 index 00000000..7f1b0aaf --- /dev/null +++ b/exercises/classes/solution/classes_sol.cpp @@ -0,0 +1,95 @@ +#include +#include +#include +#include + +class Fraction { + +public: + + Fraction(int a_num, int a_denom = 1) : m_num(a_num), m_denom(a_denom) {} + + std::string str() const { + std::ostringstream oss; + oss << m_num << '/' << m_denom; + return oss.str(); + } + + friend bool equal( Fraction const & lhs, Fraction const & rhs ) { + return (lhs.m_num==rhs.m_num) && (lhs.m_denom==rhs.m_denom); + } + + friend bool equivalent( Fraction const & lhs, Fraction const & rhs ) { + return (lhs.m_num*rhs.m_denom==rhs.m_num*lhs.m_denom); + } + + friend Fraction multiply( Fraction const & lhs, Fraction const & rhs ) { + return {lhs.m_num*rhs.m_num, lhs.m_denom*rhs.m_denom}; + } + + Fraction normalized() const { + const int gcd = std::gcd(m_num, m_denom); + return {m_num/gcd, m_denom/gcd}; + } + +private: + + int m_num, m_denom; +}; + +class TestResultPrinter { + +public: + + TestResultPrinter( unsigned int a_width ) : m_width(a_width) {} + + void process(std::string const & what, bool passed) { + std::cout << std::left << std::setw(m_width) << what << ": " << (passed ? "PASS" : "** FAIL **") << '\n'; + } + +private: + + unsigned int m_width; + +}; + +#define CHECK(printer,what) printer.process(#what, what) + +int main() { + + // create a fraction with values 3 (which is 3/1) and 1/3 + std::cout<(), reusing <=> between doubles, + and upgrade tests. +- Replace multiply() with operator*(), and upgrade tests. + +STEP 2 +- Replace TestResultPrinter::process() with operator()(), and upgrade CHECK(). + +OPTIONAL STEP 3 +- Add an inplace multiplication operator*=(), and add tests. +- Review operator*() so to reuse operator*=(). +- Ensure calls to operator*=() can be chained, the same as operator<<(). + +## Take aways + +- Do not confuse equality and equivalence. +- We can very often implement an arithemtic operator@ in terms of operator@=. +- When implementing <=>, you get <, >, <=, >= for free. +- Object-functions are very used with standard algorithms, + yet tend to be often replaced by lambdas in modern C++. + diff --git a/exercises/operators/operators.cpp b/exercises/operators/operators.cpp index 163da43e..418846c7 100644 --- a/exercises/operators/operators.cpp +++ b/exercises/operators/operators.cpp @@ -1,91 +1,103 @@ #include #include +#include #include class Fraction { - public: - // TODO: constructors and operators - private: - void normalize() { +public: + + Fraction(int a_num, int a_denom = 1) : m_num(a_num), m_denom(a_denom) {} + + std::string str() const { + std::ostringstream oss; + oss << m_num << '/' << m_denom; + return oss.str(); + } + + friend bool equal( Fraction const & lhs, Fraction const & rhs ) { + return (lhs.m_num==rhs.m_num) && (lhs.m_denom==rhs.m_denom); + } + + friend int compare( Fraction const & lhs, Fraction const & rhs ) { + int v1 = lhs.m_num * rhs.m_denom; + int v2 = rhs.m_num * lhs.m_denom; + if (v1 < v2) return -1; + else if (v1 > v2) return 1; + else return 0; + } + + friend Fraction multiply( Fraction const & lhs, Fraction const & rhs ) { + return {lhs.m_num * rhs.m_num, lhs.m_denom * rhs.m_denom}; + } + + Fraction normalized() const { const int gcd = std::gcd(m_num, m_denom); - m_num /= gcd; - m_denom /= gcd; + return {m_num/gcd, m_denom/gcd}; } - unsigned int m_num, m_denom; +private: + + int m_num, m_denom; + }; -// TODO: operators +class TestResultPrinter { +public: -void printAndCheck(std::string const & what, Fraction const & result, Fraction const & expected) { - const bool passed = result == expected; - std::cout << std::left << std::setw(40) << what << ": " << (passed ? "PASS" : "** FAIL **") << " " << result << "\n"; -} -void printAndCheck(std::string const & what, bool result, bool expected) { - const bool passed = result == expected; - std::cout << std::left << std::setw(40) << what << ": " << (passed ? "PASS" : "** FAIL **") << " " << result << "\n"; -} + TestResultPrinter( unsigned int a_width ) : m_width(a_width) {} + + void process(std::string const & what, bool passed) { + std::cout << std::left << std::setw(m_width) << what << ": " << (passed ? "PASS" : "** FAIL **") << '\n'; + } + +private: + + unsigned int m_width; +}; + +#define CHECK(printer,what) printer.process(#what, what) + int main() { + // create a fraction with values 3 (which is 3/1) and 1/3 + std::cout< athird", (athird > athird), false); - printAndCheck("afourth > athird", (afourth > athird), false); - printAndCheck("athird >= athird", (athird >= athird), true); - printAndCheck("athird >= afourth", (athird >= afourth), true); - // the operators <=, >= and > can typically be implemented just in terms of - // operator<. Can you do this as well? ;) - - // take aways on operators: - // * we can very often implement an arithemtic operator@ in terms of - // operator@= - // * it usually suffices to implement operator< and operator== and derive the - // other relational operators from them. C++20 will do part of this automatically. + const Fraction third{1,3}; + std::cout<0); + CHECK(p2,compare(third,Fraction{2,4})<0); + + // multiply + std::cout< -#include -#include - -class Fraction { - public: - explicit Fraction(int i) : m_num(i), m_denom(1) {} - Fraction(int num, int denom) : m_num(num), m_denom(denom) { - normalize(); - } - - friend std::ostream& operator<<(std::ostream& os, Fraction const & f) { - os << f.m_num << "/" << f.m_denom; - return os; - } - - Fraction & operator*=(int i) { - m_num *= i; - normalize(); - return *this; - } - - Fraction & operator*=(Fraction const & o) { - m_num *= o.m_num; - m_denom *= o.m_denom; - normalize(); - return *this; - } - - friend Fraction operator*(Fraction f, int i) { return f *= i; } - friend Fraction operator*(int i, Fraction const & f) { return f * i; } - friend Fraction operator*(Fraction a, Fraction const & b) { return a *= b; } - - friend bool operator==(Fraction const & a, Fraction const & b) { - return a.m_num == b.m_num && a.m_denom == b.m_denom; - } - - friend bool operator<(Fraction const & a, Fraction const & b) { - return a.m_num * b.m_denom < b.m_num * a.m_denom; - } - - friend bool operator!=(Fraction const & a, Fraction const & b) { return !(a == b); } - friend bool operator>(Fraction const & a, Fraction const & b) { return b < a; } - friend bool operator<=(Fraction const & a, Fraction const & b) { return !(a > b); } - friend bool operator>=(Fraction const & a, Fraction const & b) { return !(a < b); } - - private: - void normalize() { - auto const gcd = std::gcd(m_num, m_denom); - m_num /= gcd; - m_denom /= gcd; - } - - unsigned int m_num, m_denom; -}; - -void printAndCheck(std::string const & what, Fraction const & result, Fraction const & expected) { - const bool passed = result == expected; - std::cout << std::left << std::setw(40) << what << ": " << (passed ? "PASS" : "** FAIL **") << " " << result << "\n"; -} -void printAndCheck(std::string const & what, bool result, bool expected) { - const bool passed = result == expected; - std::cout << std::left << std::setw(40) << what << ": " << (passed ? "PASS" : "** FAIL **") << " " << result << "\n"; -} - -int main() { - // create a fraction with values 3 (which is 3/1) and 1/3 - const Fraction three{3}; - const Fraction athird{1, 3}; - - // print the fractions - std::cout << "Three: " << three << '\n'; - std::cout << "One third: " << athird << '\n'; - - // multiply fraction with an int - // the printAndCheck function requires operator<< and operator==: - printAndCheck("One third times two", athird * 2, Fraction{2, 3}); - // ensure symmetry - printAndCheck("Two times one third", 2 * athird, Fraction{2, 3}); - - // multiply two fractions - printAndCheck("Three times one third", three * athird, Fraction{1, 1}); - // normalize the fraction after multiplication so the above statement - // prints 1/1 instead of e.g. 3/3 - printAndCheck("Three times one third", 3 * athird, Fraction{1, 1}); - - // multiply in place - Fraction f = athird; - f *= 2; - printAndCheck("One third times two", f, Fraction{2, 3}); - - f *= athird; - printAndCheck("Two third times one third", f, Fraction{2, 9}); - - // you might have some redundancy between the implementation of operator* and - // operator*=. Can you refactor your code and implement operator* in terms of - // operator*=? - - std::cout << std::boolalpha; // print bools as 'true' or 'false' from now on - - // more equality comparisons - printAndCheck("One third == one third", (athird == Fraction{1, 3}), true); - printAndCheck("One third != one forth", (athird != Fraction{1, 4}), true); - printAndCheck("One third == two sixth", (athird == Fraction{2, 6}), true); - printAndCheck("One third != three sixth", (athird != Fraction{3, 6}), true); - // try to implement operator!= in terms of operator== - - // more comparisons - const Fraction afourth{1, 4}; - printAndCheck("athird < athird", (athird < athird), false); - printAndCheck("afourth < athird", (afourth < athird), true); - printAndCheck("athird <= athird", (athird <= athird), true); - printAndCheck("athird <= afourth", (athird <= afourth), false); - printAndCheck("athird > athird", (athird > athird), false); - printAndCheck("afourth > athird", (afourth > athird), false); - printAndCheck("athird >= athird", (athird >= athird), true); - printAndCheck("athird >= afourth", (athird >= afourth), true); - // the operators <=, >= and > can typically be implemented just in terms of - // operator<. Can you do this as well? ;) - - // take aways on operators: - // * we can very often implement an arithemtic operator@ in terms of - // operator@= - // * it usually suffices to implement operator< and operator== and derive the - // other relational operators from them. C++20 will do part of this automatically. -} diff --git a/exercises/operators/solution/operators_sol.cpp b/exercises/operators/solution/operators_sol.cpp new file mode 100644 index 00000000..29c1215a --- /dev/null +++ b/exercises/operators/solution/operators_sol.cpp @@ -0,0 +1,135 @@ +#include +#include +#include +#include +#include + +class Fraction { + +public: + + Fraction(int a_num, int a_denom = 1) : m_num(a_num), m_denom(a_denom) {} + + std::string str() const { + std::ostringstream oss; + oss << m_num << '/' << m_denom; + return oss.str(); + } + + friend bool operator==(Fraction const & lhs, Fraction const & rhs) { + return lhs.m_num == rhs.m_num && lhs.m_denom == rhs.m_denom; + } + + friend bool operator!=(Fraction const & lhs, Fraction const & rhs) { + return !(lhs==rhs); + } + + friend auto operator<=>( Fraction const & lhs, Fraction const & rhs ) { + return ((lhs.m_num*rhs.m_denom)<=>(rhs.m_num*lhs.m_denom)); + } + + Fraction & operator*=(Fraction const & other) { + m_num *= other.m_num; + m_denom *= other.m_denom; + return *this; + } + + friend Fraction operator*( Fraction lhs, Fraction const & rhs ) { + return lhs*=rhs; + } + + Fraction normalized() const { + const int gcd = std::gcd(m_num, m_denom); + return {m_num/gcd, m_denom/gcd}; + } + +private: + + int m_num, m_denom; + +}; + +std::ostream & operator<<(std::ostream & os, Fraction const & f) { + return (os<Fraction{2,6})); + CHECK(p2,std::is_gt(third<=>Fraction{1,4})); + CHECK(p2,std::is_lt(third<=>Fraction{2,4})); + CHECK(p2,(third>Fraction{1,4})); + CHECK(p2,(third=Fraction{2,4})); + CHECK(p2,(third>=Fraction{1,4})); + CHECK(p2,(third<=Fraction{2,4})); + CHECK(p2,(third>=Fraction{1,3})); + CHECK(p2,(third<=Fraction{2,3})); + CHECK(p2,!(thirdFraction{2,4})); + CHECK(p2,!(thirdFraction{2,3})); + + // multiply + std::cout<Fraction{1,1})); + CHECK(p3,std::is_eq((3*third)<=>Fraction{1,1})); + CHECK(p3,((3*third).normalized()==1)); + + // multiply in place + std::cout<1)); + CHECK(p4,one.normalized()==1); + CHECK(p4,one!=1); + + // end + std::cout< Date: Thu, 13 Feb 2025 16:18:24 +0100 Subject: [PATCH 132/156] Add exercises/classes to the CI. --- .github/workflows/build-exercises.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-exercises.yml b/.github/workflows/build-exercises.yml index 9e3f3942..c67368f6 100644 --- a/.github/workflows/build-exercises.yml +++ b/.github/workflows/build-exercises.yml @@ -39,8 +39,9 @@ jobs: - NAME: "memcheck" - NAME: "modern_oo" - NAME: "move" + - NAME: "classes" + SKIP_DEFAULT: true - NAME: "operators" - SKIP_DEFAULT: true - NAME: "optional" - NAME: "polymorphism" - NAME: "python" From 63d102a5b4538d6ce04cb690308d67e6c819963c Mon Sep 17 00:00:00 2001 From: David Chamont Date: Thu, 13 Feb 2025 16:43:57 +0100 Subject: [PATCH 133/156] Typos. --- exercises/ExercisesCheatSheet.md | 2 +- exercises/operators/README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/exercises/ExercisesCheatSheet.md b/exercises/ExercisesCheatSheet.md index 71ec9db8..702d8874 100644 --- a/exercises/ExercisesCheatSheet.md +++ b/exercises/ExercisesCheatSheet.md @@ -73,7 +73,7 @@ You may discuss with the students: reusing versus performance. - object-functions. - for what concerns the related operators, such as * and *=, - the choice to be made consitent reuse or performant + the choice to be made consistent reuse or performant specialization of each operator. ### Polymorphism (directory: [`polymorphism`](polymorphism)) diff --git a/exercises/operators/README.md b/exercises/operators/README.md index 5cfdafd2..5c1a1c60 100644 --- a/exercises/operators/README.md +++ b/exercises/operators/README.md @@ -17,10 +17,10 @@ OPTIONAL STEP 3 - Review operator*() so to reuse operator*=(). - Ensure calls to operator*=() can be chained, the same as operator<<(). -## Take aways +## Take away - Do not confuse equality and equivalence. -- We can very often implement an arithemtic operator@ in terms of operator@=. +- We can very often implement an arithmetic operator@ in terms of operator@=. - When implementing <=>, you get <, >, <=, >= for free. - Object-functions are very used with standard algorithms, yet tend to be often replaced by lambdas in modern C++. From 9e1d24a46017e9b323c09c2da2a331974899e7f6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 13 Feb 2025 15:44:55 +0000 Subject: [PATCH 134/156] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- exercises/classes/.gitignore | 2 +- exercises/classes/README.md | 1 - exercises/classes/classes.cpp | 2 +- exercises/classes/solution/classes_sol.cpp | 12 ++++++------ exercises/operators/.gitignore | 2 +- exercises/operators/README.md | 3 +-- exercises/operators/operators.cpp | 18 +++++++++--------- exercises/operators/solution/operators_sol.cpp | 12 ++++++------ 8 files changed, 25 insertions(+), 27 deletions(-) diff --git a/exercises/classes/.gitignore b/exercises/classes/.gitignore index 8a8577fc..9c420365 100644 --- a/exercises/classes/.gitignore +++ b/exercises/classes/.gitignore @@ -1 +1 @@ -classes classes_sol \ No newline at end of file +classes classes_sol diff --git a/exercises/classes/README.md b/exercises/classes/README.md index 881e2963..26aba0a8 100644 --- a/exercises/classes/README.md +++ b/exercises/classes/README.md @@ -30,4 +30,3 @@ OPTIONAL STEP 4 - Transform the private normalize() into a public const normalized() method which return the normalized fraction. - Add some tests to check normalized(). - diff --git a/exercises/classes/classes.cpp b/exercises/classes/classes.cpp index dbf7e45e..5766419c 100644 --- a/exercises/classes/classes.cpp +++ b/exercises/classes/classes.cpp @@ -72,4 +72,4 @@ int main() { std::cout<(), reusing <=> between doubles, and upgrade tests. -- Replace multiply() with operator*(), and upgrade tests. +- Replace multiply() with operator*(), and upgrade tests. STEP 2 - Replace TestResultPrinter::process() with operator()(), and upgrade CHECK(). @@ -24,4 +24,3 @@ OPTIONAL STEP 3 - When implementing <=>, you get <, >, <=, >= for free. - Object-functions are very used with standard algorithms, yet tend to be often replaced by lambdas in modern C++. - diff --git a/exercises/operators/operators.cpp b/exercises/operators/operators.cpp index 418846c7..caa361c2 100644 --- a/exercises/operators/operators.cpp +++ b/exercises/operators/operators.cpp @@ -18,7 +18,7 @@ class Fraction { friend bool equal( Fraction const & lhs, Fraction const & rhs ) { return (lhs.m_num==rhs.m_num) && (lhs.m_denom==rhs.m_denom); } - + friend int compare( Fraction const & lhs, Fraction const & rhs ) { int v1 = lhs.m_num * rhs.m_denom; int v2 = rhs.m_num * lhs.m_denom; @@ -26,11 +26,11 @@ class Fraction { else if (v1 > v2) return 1; else return 0; } - + friend Fraction multiply( Fraction const & lhs, Fraction const & rhs ) { return {lhs.m_num * rhs.m_num, lhs.m_denom * rhs.m_denom}; } - + Fraction normalized() const { const int gcd = std::gcd(m_num, m_denom); return {m_num/gcd, m_denom/gcd}; @@ -51,15 +51,15 @@ class TestResultPrinter { void process(std::string const & what, bool passed) { std::cout << std::left << std::setw(m_width) << what << ": " << (passed ? "PASS" : "** FAIL **") << '\n'; } - -private: + +private: unsigned int m_width; }; #define CHECK(printer,what) printer.process(#what, what) - + int main() { // create a fraction with values 3 (which is 3/1) and 1/3 @@ -67,7 +67,7 @@ int main() { const Fraction three{3}; const Fraction third{1,3}; std::cout<0); CHECK(p2,compare(third,Fraction{2,4})<0); - + // multiply std::cout<( Fraction const & lhs, Fraction const & rhs ) { return ((lhs.m_num*rhs.m_denom)<=>(rhs.m_num*lhs.m_denom)); } - + Fraction & operator*=(Fraction const & other) { m_num *= other.m_num; m_denom *= other.m_denom; @@ -37,7 +37,7 @@ class Fraction { friend Fraction operator*( Fraction lhs, Fraction const & rhs ) { return lhs*=rhs; } - + Fraction normalized() const { const int gcd = std::gcd(m_num, m_denom); return {m_num/gcd, m_denom/gcd}; @@ -62,15 +62,15 @@ class TestResultPrinter { void operator()(std::string const & what, bool passed) { std::cout << std::left << std::setw(m_width) << what << ": " << (passed ? "PASS" : "** FAIL **") << '\n'; } - -private: + +private: unsigned int m_width; }; #define CHECK(printer,what) printer(#what, what) - + int main() { // create a fraction with values 3 (which is 3/1) and 1/3 @@ -78,7 +78,7 @@ int main() { const Fraction three{3}; const Fraction third{1,3}; std::cout< Date: Thu, 13 Feb 2025 17:37:38 +0100 Subject: [PATCH 135/156] Desperate cosmetic. --- exercises/classes/classes.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/exercises/classes/classes.cpp b/exercises/classes/classes.cpp index 5766419c..15e24023 100644 --- a/exercises/classes/classes.cpp +++ b/exercises/classes/classes.cpp @@ -72,4 +72,3 @@ int main() { std::cout< Date: Fri, 14 Feb 2025 11:04:27 +0100 Subject: [PATCH 136/156] Bug fix : a single pattern by line in gitignore, and remove executable from git. --- exercises/classes/.gitignore | 3 ++- exercises/classes/classes_sol | Bin 97176 -> 0 bytes 2 files changed, 2 insertions(+), 1 deletion(-) delete mode 100755 exercises/classes/classes_sol diff --git a/exercises/classes/.gitignore b/exercises/classes/.gitignore index 9c420365..a5a19752 100644 --- a/exercises/classes/.gitignore +++ b/exercises/classes/.gitignore @@ -1 +1,2 @@ -classes classes_sol +classes +classes_sol diff --git a/exercises/classes/classes_sol b/exercises/classes/classes_sol deleted file mode 100755 index f60e4f920b21a2772eb58974b308c1d3a9709ca0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 97176 zcmeGFd2|%j)&`89>h9{(NpPjbh*Zbb}`>pT$!(OZUoW1w6_t|Hk zp-!Eysy@4T(pZ2>s36{{pxDk2q4dOBrO=?kA!{2|Z;2d&DOep0wdZ?~zp+tjntNHd;RYQ>Yx&{1I8 z4NkKlqmPva>n%0)g3~cdO;{KZkE?kJFGM7ZKY=MVnA)pqWs(ewN?FVYgRO_>%Xobzkhyi=IWK1IqU-Ym5PJ< z)VL`#1)60)@l12VwNcTQJ(5w^Bst+rZ@c{3UlzXJ_1EJ2Z%w{o--%CVtshMo@|$!B zLm$GMO>Wb@ks}PpL)(FTsvsVH`rvrI`qjGJi-(;Px6?nGneBYN4#Uyy@E?H_?eTY` zqV4hLbztXqIM*J2J1Wy2e`5#b{@wxK)q(xy4)~9D;Qxz=L3{pO-GQC$2z-0^PdbQ$ z(LsGDc7X5NLAif*P%h0Q?fEmdgL>WDf&J1B>|fG>olzacb7}|mt?!^6<2&GQ@4)_w z4(j_;2maG|O2rZUsp}vPn>(wzb>k~%loyxfl~+RRzwlvDIci(cP=Uh#I|JF-uuxgCs-m){;q>A<%lCFF-JbI^ z%4cN3{rvK>hP?8!>V~!dgT4w{I}tFA3@V>KvEvAo<(4B#GqTHzi@BmJYgZT7aE{ty zOm^`aA|^Uoad05cXhtjAZ5u`TH4p%0$5A=z+z>Yi5*}6`)CSvKFtbUt3XMRbGRkP|>gwUASV2DyN`k4 ztbeOU_+JhsyBl*Wa*K?~;pX_ik0gYky((JXIhyx>>D*w7Fve;_b@B8%j1Z1WeRadq z`jyn*JMOdX3?kLp>~IH~`~TKk+cEIJtPCct$>po78_H{|S1f5*$|L^2s6loX%v9B^ zUbS*{wb@R&l`9(?%;;bMSUm>uu{u?Q-Ra6OYy5YiWB+ScR#w!id5<~_#`NIwa&C|E z+LcQ%bywHdudKH_!vA?<&nX{Si!#cW*5FKnj#FAWePY=_OzbmPtgS)SrdO|Sti$<) zd&1%x8VY9+iM2JIHt0-LS5dRV1fb)rt7#Azp@=zn08}o=Ib(VG;)p0h2>y^@;ryBy;!{E_}(4U&}BG9olHDLlJ95ZC{E*V{7h-uHdp0%zc zQ`5<+5Zle`Rg16ZDE`hM{-GX*TH{&fg&i3*3yhP2OWIs z57y^B2OmpB`*X;_$I{gPv^e-ww)Hvc;G0dzq7x3j)n+U(>q}U3i-Xxd2Ok~O{zN+X zew&N^9S0vB*8ZeA_~AAeZSCMkIQUr(KJ{1YQ{do7Sxlrw4!-mHsKmjKao|fGd~*wl zrL!IUI0t^AgCFnUFLm$}9Q;)dexifF&cRP|@Haa6ogDo09DH-jily5f{1gX%r-R?w z!QbuRcXjY@b@0<1{5=kSHwS;OgWui3-|yh}bnySq{vCn8Bk*?w{*J)k5%@a-e@Ec& z2>cy^za#MfUIc!O=<-|1=I?wZ&HDQzgecjvzrl6#V9DlZd{47eC-W{IF2wPZ>HkC$ z(Nz$BDM^kW{_Nz*liQi53)$m`U$<$xfIWWrNt>n%*W-upwQ0IwJ%0E)o2CoZw>nuCQskKs|nVnoZLN!12Q)ZJI7rj~~vqX}Ul?emKph z>B98*;V7G?3)16J4KA_Xp4$hPI{~gXp>-x;luSA4Ja#q9+H@#XF=s$+i<8d&etgsG3rdX}7(Og$kd4@Gp{NVuoX6!_B^pSO&XK7W-o9W8nC z-y=$%JmD_Uo-29%uZCC{NH-1mP99p!{nFB>`Dx=Y>TaSjV`j2U?zh<&te%)vprr?9n38S98y_LYJ`xc(Tyb}oY`c_H zN}ApwZmPv)(-)Ygb76X4s;PK@%4vEU7WbEIo4L_c{07q+v!K}YX^V?AXl5j%m$GMo zBj5A~d0D)h@*61MtUrWbl~q+z%<_I>(3V>GwJ+H;@-pT{%U4xPv*ej@IpU%BV00%L zy_E}_xl{QUb}OcjQ3w^vp-M_Fe%%Ic=Vva@x|EyKA3F-BduSxqOZY$vu;wH{V(ZZ|9Z zG3INtV&xq;akXmX{iOZtZ(L!vbhYVFYbU5IFV>M(W^ zcK@TU#^dEZ_~i&gMr$W_<6LUC#hcvlZ989-!-+bF6H%5Et-^3BJHcJj@?chL4{l>U zI}C#Y9!%@NgNwM6sqTN|L?8?okvGkHVm{S@CYrN2cc5h!ySZf*jZQTu9cal^Ms_|z ztEqjoB%{uCJJw37>)5S!3u>_WsOE^-FKo{CcsJG~X3VbTF2XUR!t4S2F?R;#@nDC? zAFF(j6X|W8SOg~=9yGT0V0gfT&K-C#*Wtm#zXW17*Yu`!7;eB45~Gs`N;9=!6Z#Ji zYdb94;iU5DJPOww#^eR=87d~}$|JV)0_B_a>A7TqT5&Ju z4zz4%(3S>j#VoVEmMSAV)tSO-#V@fUh9l>xX~E*Y%3OAFqd6ExQKXwtPgOV6m&eEh zs6N+i%W@P()$?%mE@hHWBVo~j8s5fTiEBvC*{%K!x1*}z=>Jg6ZF^rbSsdgy{hHX; z?|9|+Mv|Bgo=@%5*6%-nZ0+|Xj+xW%e_(ZOw#+f^6K(w-;PAWo=T?6Av;5}swRL80 zz!*XZ;h}TZ|BC!>>*VE@lT;gwIJRha93$Y~^bXwHt~%#_(*Euza!*;>&aNV+t$ceA zS5JYMS}TmFn9I|W71R9o-EBeLTF3MRm*b4-R$RfDF}<2QWZRg2NY<(6!0AEkwA~lp zBeGeq$R;Dy;SX@`K+Cld>_tZxCCxKis!B3qc|jF%P9$n^*o!Y(bXf}<*!}d!lP8bJ z0CP7L_9B=iP47{502~iU*_AtkRCpONjvP`de;^yAa(a6zu>qAA+Nz8VQsH^!vw&ll zwN;5}Pv!1_N@ZJ>L&sZJpG!G2ppw;A<*xQrN&+f>A{$iwGul&$3#d@MgH*<~r}82Lis?NF&v?2pq&$iVX z)mlpp*^j|AgK%+Mm5A0VwtKe(wB|vpD1Lc^F))2_<>qmzbd}{!-brldB=sIGc>fbc;DB&mokt%bvsnoMQfa8l(v|mZn<4du7Q_}R{LL|YL zs@t}#V&Q?7yMLgPw-Bf~vPAJ!4c~%fANmVS9cWoXFp7af7J2B3^4*p_N}EgCcB!(- z%ZrEqjc#R{BmHl_CmM0Z9Iq~#8+so}vqzon&J)0yqooSATV8`56v_p(?*52JNmHYW z28H5ivl#qTV-j*FnoB**DDr?K_fl^@qH~80#EJS-kbaRT;+})7h`mr)A^OR|Peoj^ z-=VhoJ2ecN8V@;xdV;S1(QC+)L(QV;^@w|(X9l}+h;1Fj$?>SV>g`F` zu{~&#bhL8BL)17&BOVe3s!i=0p+fD(`9SeebRG1alFh|Owdaa|5NNOWID8t#^as=Z z3o&|e`E<_y#&=j4)TjphdLa-$YjOe$yEusmx%P%s;r`BQW8PsD72a7gh_8{p*8BW_}1 z&=h|+q_|~GG#R1kvjyD}b!b8-DE_WbF$zXe;XH$(lfL9o4f_RcQL2UQcXXB1Jad1Eb`Wz4O)WSZ9s&mkmc(q0H?~$n zbfk+l!F}6}W|Lqw0YPQE&N-oM=7GnWsLUsPvx=s7>O9Rj8K}8>IaqVc#{*J)k5%@a-|KE#%dip^5 zRhTMDN0ya|zI{{2jvPNJwQpZheOhBhZErj>QeEATzx&v%n))iR@Eu?gYHWQ)Wkb!% z6=x3I(2<~DwnIc_Y@O_W0WF(3a6{{&Z2_Sz7t$kVxlFxhh$+DkdAzhPjH=x zeD0x>Coe!c2I-BIetz=gB&7YnIC;{Ci~Rd>U3Lh2iy^qgrw7oxA$<(;g-Aa_x(4YV zNH0K|f(w&tkPb!q8q#@41vVwtBVCMi7t)K7K8Eyqq#q%D5oro`{_exR#~7r?kyat? zgUy|DkY0xLMx>G0>v{%hKcrtGr9H+h`1cpmQlz!m3S5Phws*H9y%p&mq+cUFh;%1* zWsf3#2Wcega|QO13y{8wbT-l$`~a~LX&e0}cv=393&`(;d>`b!o%-bgIkB}fN+)qk%BytzuAOYPC$$?LH$%S# zspl6oo>fN4X1D9zfSp)~7Gqo#0cT^@2IRSrZ-so2Q@$b~p8@&Rkk>iot||sl92y}1 z7V^_u$yeF(OCTSE@kPJO+vQJJ_EW)n0P-TpsXy5AV$|Upg`s-VbK;#pJ$Z7gA9d{t z1xH=ojeffgn($;Kz2z zS3=&&DW4XQ?}7X!Twcv`%3W#_p!PZlxrU2T+$RyRU#j$pb@HSZJ_z&Pv{4V@0Ywct z=Dnf~oFK%7TJQ5?#C|RM=V7nGyY-_n;yt(iVT^dzqu&rKKKAGr z#)=np{he6xxvoDMD_-{MO>yE&ul`f4cwOp`#figGza>t*>C=CR6Gwdd2XSIo2n=rt z)vu2iSBL7`;>Ed!{&u{$*3kFIi!1#4c?sfPzy4#q_}mZR?_v6*3F4pO`ppUA{s{e8 zf_N!H|0qGc5vkvjD87x5YEkP*2Ilelap7a zYn|p*3h|t#Z*^%u5bp|C=nXFMpbJ?v=-;2eBk*?w{(lvL)O2OZdS2LiKG+&)^z1Ty zESjE`cGC20G<|UTQlC_n;NA@WlnzlT&vVFH&oA>i6STGF;&~Lb^}I68k@TT86@7mG z>m=>%i9I-v&R zF$J_9q>pJ%(5=DrSrw&Hi(gpc!Y(V*=S3(S zHvO2k{KTo4=`2%@Wirz^t^EJxW4#A0*mzc|;uM)_shKV`(^Y1=(M-3S>25RKW2XDf z^q`p@GSj1GD$)dhBF!|_OtZ|i$V^MkbfKB9GSiJ_y4_57o9P}i-EXD`&Ge9&9yL?z zWk8YLlpm>Ps;K||+qbZ_E?%QhnA&^hqQ(^sjj7q$ct=83|LjI4v(L)O$;`^_W3q)G zeN=T*)rtC;L-}WOEOyCJrg_PR>^zg^B@gKOAo@I$jy65I(xkIZ`lTTH50hSO$`=h( znSLgHp-Edq{2G()ZOWfB=@yf|o37XJDdKM-{%z8{dP5Ms77H^rf87A?YNn7@ong#I^89L{hG%txk-)PcSJU=(-`%L?n6sQa@aglw) zq@OnBmkw4L)9p5|kcu#;%6Jn`_g2$~m!L=onzS`lve5B0x|XIzjXT5Ard~pD*QJTq z><~6KHr0L63S8qxdNMMQcsy(2TCC6W8)iu`e@3Dg$Drib6HbLvtWQ3&Oo*Dx8nI3f z6PJQjD9;d_5rsF5R5?%K+BHJ#g3wpkWac7aTs{HaWj?)pJ??jkO(5+dzQ}Ox=~P^i zfGG1sM!DZdW@tPD8W|l!h@sCUARiM-0O36d_aY-CT`LLidW1DHR(}|Ij~M0wkB;Hw zs9VHp-p>FIA=Yw_UbCV>gpiv4Y$~+k+_wXzA3#3J8qu^*giLM#q=AMpC zjhJlT%NSbT%P>vH3^WVwf>_1mhcux5eco@nff&R@q_-G7DW-slMDJDbBxW!Zson$( zhL}PodVBl#05OD#EN^dg!5JgOsc>jUk7&DTIQg7%45Tlrw z?R{lBh%xc=X9=;;dr>2Zv9XIlEcGUrfhb|GS9$l4*W;OJ@SZgm!~|p76d~4mBNl>~ z98GTs-RSjT)Wl4QsGlsvKfKQ)#4%HSOJHrY_Y4g4m}wDfL7eCP2N^guY(5NZ_YTbm zF*jioBs;wa(aB=wB{hTC?cKHx#C&$=R`0hcAZ9@b^^85W_$jw>>#5#4dy zjB8-k9e0t*-)@w#e21};(~Avy0>T~lPlKM?aK~L@e8TCa#&4WnW+V(H{^dpir#p?Q zoL*tf9%CS<_ZelJ-fx`6=>x_UoIYqg!0AKAYn(o8e9P%xLmxr< z|1#d-^bwPEw7#DK-q;U_YPa7|B`iyae(`SvCk);2e zk;~};V+N? z)50mfoqFI>6LIR)TMK8sK3X{I^~HrY^xW}z#vAC??)ZEov6Rw5#z3TT3+7<;n=sP< z1eTooGz_hTG5yCt(4{-&$40%0PFxAuxj44ra7~0zbeV>+nlLftqrOUd6C`)o(uDFE zs{|RDQC_}=Gw9m0AdX7`o=WTQ4Js|Xj!VnKN%3_6f5!1U*(-IH_I8?*#y~p>hmy7} z4R1qw2Fm*WDj1!`B`4B^pO~n1!t^C(dJ&P0p)+S-+`SW8_f-X)GUkWI^?-fNs0?j{ z?YvX*CF1sm5o<~4dBj@8tV3uP%~&3K6|o2^W<`X z4+H*1fV9(56YVUjPGXmIWansUG>wOlaCY@+VyTwjhz&OYekC{|6?}GW1NJO08K;DF zSF=MH?ui23ph;Se(5Zmlq@-;oW&RpY{)L~4sab2%^9@`6h}b(6=^- zi=$wO@MMb5v#?aJVy7dX+BTp?;-X4q=W1zG)ez!`tKfhJKeIQjIF3%xmaj#YVux8?rduoMxyqvCOsa-ILlHHp|6ChGqG@Y8erT3 zWA08_#>1Ru8&7kZW4y*`uCaU?$@7f0oaP&wIUQtN#OYwe;Iz<4;B<)5oztPl08WP+ zUvN6Yc!|@I#)oWol<^Ixqm3Uq9b=s2bgXd|Xr)PWYii|Gv!{n5|bloMjNO#4%ZZNaRlD>CsH1irC5}ZGz*e^TN>3!y8n^`PE*n; zkj!vMdqMiR{K&Li3rW2#jcn`<>FTfo1XPQnSM#PkDbIsj1i2i?)iyM08X}PLth^i7 z>m+>;$D;x1NYZ^lHe+TW>6yXDG-efL&`rRWpyMXb>qs$jO+%$jC!Do@|YXdS^9^{3=VkDaiW} z)5CSDCZ1oxP7#`1f|eo+Cvf~_iz5ZPPs$3_MLh4Ky;7tmdo5L%9ym+&#i2|^Jdpu$ zm?q~{>4cYm&oI0@Z&`h7w zLz4?8skq(%Ih`oEc#WkyaTk;WiDm1CXW>< zy>p;*k*&u=UwJZ3lfTYUm|G!#+{OevaiC{v@?-RM^5h*Lk9L4I!$D`}lnXV9@Nw@A z!PrW|5eSD9c(EqKF_@{`9DqjIK%Pg4Ej(=TQcdPBQ^2_Zt+IjSs51zR-l@qa$0&3Y zkXN)t3(stFbeAUkG$`PG06k>`sU=KD8Ms@Mi8y7GM;`)o#0EMXW#A2(d}gu&dLmJE z9IEQUjxzdYO%6kM=K2FUsx4Z0e!xVQa=Rv<#sv`p=K{3c209#N;N6<+iGe`Ca{#); z209#N;C-6>&;;HE&{H-r*ilA5q{(s&Ypy?#N7|x==lPj%^bt)SKUD##KgQx{)AS5{ zLX#Dv6|g@*!)&0#Q3gJ($$f?^Sv(0)Y_wJNU`H8^1>1kJ6uLi< z!`h;SXDH_7lutBCQyrO|1<+y}=x~&QUug38H41n(Ko{9ShocPqT9Y-Y3V16(kK4dt zM;ZOCCeNL&(C+~Gbz8Iu*HGV-pENlQb1Y31UOM@b$7&4CSxzz0qG@3x=JdomRk-4) zFrU3b&755�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 From ab86d3298d09894c9dc0adfe11a6af50edea2ddc Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Tue, 18 Feb 2025 16:41:54 +0100 Subject: [PATCH 137/156] Cleaned up .gitignore files and exercies compilation --- .gitignore | 52 ------------------------ CREDITS.md | 2 +- exercises/.gitignore | 11 +++++ exercises/CMakeLists.txt | 2 +- exercises/Makefile | 14 ++++--- exercises/asan/.gitignore | 2 + exercises/basicTypes/.gitignore | 2 + exercises/callgrind/.gitignore | 2 + exercises/concepts/.gitignore | 1 + exercises/condition_variable/.gitignore | 2 + exercises/constness/.gitignore | 1 + exercises/control/.gitignore | 2 + exercises/cppcheck/.gitignore | 2 + exercises/debug/.gitignore | 2 + exercises/functions/.gitignore | 2 + exercises/header_units/.gitignore | 3 ++ exercises/helgrind/.gitignore | 2 + exercises/hello/.gitignore | 1 + exercises/loopsRefsAuto/.gitignore | 2 + exercises/memcheck/.gitignore | 2 + exercises/modern_oo/.gitignore | 2 + exercises/modules/.gitignore | 3 ++ exercises/move/.gitignore | 2 + exercises/optional/.gitignore | 1 + exercises/polymorphism/.gitignore | 2 + exercises/race/.gitignore | 3 ++ exercises/smartPointers/.gitignore | 10 +++++ exercises/stl/.gitignore | 2 + exercises/templates/.gitignore | 2 + exercises/valgrind/.gitignore | 2 + exercises/variadic/.gitignore | 2 + exercises/variant/.gitignore | 1 + exercises/virtual_inheritance/.gitignore | 2 + 33 files changed, 83 insertions(+), 60 deletions(-) create mode 100644 exercises/.gitignore create mode 100644 exercises/asan/.gitignore create mode 100644 exercises/basicTypes/.gitignore create mode 100644 exercises/callgrind/.gitignore create mode 100644 exercises/concepts/.gitignore create mode 100644 exercises/condition_variable/.gitignore create mode 100644 exercises/constness/.gitignore create mode 100644 exercises/control/.gitignore create mode 100644 exercises/cppcheck/.gitignore create mode 100644 exercises/debug/.gitignore create mode 100644 exercises/functions/.gitignore create mode 100644 exercises/header_units/.gitignore create mode 100644 exercises/helgrind/.gitignore create mode 100644 exercises/hello/.gitignore create mode 100644 exercises/loopsRefsAuto/.gitignore create mode 100644 exercises/memcheck/.gitignore create mode 100644 exercises/modern_oo/.gitignore create mode 100644 exercises/modules/.gitignore create mode 100644 exercises/move/.gitignore create mode 100644 exercises/optional/.gitignore create mode 100644 exercises/polymorphism/.gitignore create mode 100644 exercises/race/.gitignore create mode 100644 exercises/smartPointers/.gitignore create mode 100644 exercises/stl/.gitignore create mode 100644 exercises/templates/.gitignore create mode 100644 exercises/valgrind/.gitignore create mode 100644 exercises/variadic/.gitignore create mode 100644 exercises/variant/.gitignore create mode 100644 exercises/virtual_inheritance/.gitignore diff --git a/.gitignore b/.gitignore index d69a7982..22b9f4ba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,55 +1,3 @@ -# latex related, Course -C++Course.* -!C++Course.tex -_minted* - -# latex related, exercise intro -exercisesIntro.log -exercisesIntro.nav -exercisesIntro.out -exercisesIntro.snm -exercisesIntro.toc -exercisesIntro.vrb -exercisesIntro.pdf - -# exercises -build -*.a -*.o -*.so -*.sol -*.sol? -exercises/*aux -exercises/callgrind/fibocrunch -exercises/control/control -exercises/loopsRefsAuto/loopsRefsAuto -exercises/operators/operators -exercises/concepts/concepts -exercises/constness/constplay -exercises/cppcheck/randomize -exercises/debug/randomize -exercises/functions/functions -exercises/helgrind/fiboMT -exercises/hello/hello -exercises/lambdas/randomize -exercises/memcheck/memleak -exercises/move/trymove -exercises/optional/optional -exercises/polymorphism/trypoly -exercises/race/racing -exercises/stl/randomize.nostl -exercises/templates/playwithsort -exercises/valgrind/randomize -exercises/variant/variant -exercises/virtual_inheritance/trymultiherit -exercises/smartPointers/smartPointers - -# tools -CMakeCache.txt -CMakeFiles -cmake_install.cmake -callgrind.out.* - # just for the allcontributors cli installation... package-lock.json package.json diff --git a/CREDITS.md b/CREDITS.md index 00130408..df274922 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -1,7 +1,7 @@ Credits ======= - - Adaptations for CERN sessions (2020, 2021) + - Adaptations for CERN sessions (2020, 2025) * [Sebastien Ponce](https://github.com/sponce) [CERN](http://cern.ch)/[LHCb](http://lhcb.cern.ch) * [David Chamont](https://gitlab.cern.ch/chamont) [IN2P3](https://informatique.in2p3.fr) * [Attila Krasznahorkay](https://gitlab.cern.ch/akraszna) [CERN](http://cern.ch)/[Atlas](https://atlas.cern/) diff --git a/exercises/.gitignore b/exercises/.gitignore new file mode 100644 index 00000000..b624e076 --- /dev/null +++ b/exercises/.gitignore @@ -0,0 +1,11 @@ +# generic files and directories +build +*.a +*.o +*.so + +# tools +CMakeCache.txt +CMakeFiles +cmake_install.cmake +callgrind.out.* diff --git a/exercises/CMakeLists.txt b/exercises/CMakeLists.txt index 7f42f450..6438cc2d 100644 --- a/exercises/CMakeLists.txt +++ b/exercises/CMakeLists.txt @@ -13,7 +13,6 @@ if( "${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}" ) endif() # Include the exercises that (should) work on all platforms. -add_subdirectory( hello ) add_subdirectory( asan ) add_subdirectory( basicTypes ) add_subdirectory( callgrind ) @@ -23,6 +22,7 @@ add_subdirectory( control ) add_subdirectory( cppcheck ) add_subdirectory( debug ) add_subdirectory( functions ) +add_subdirectory( hello ) add_subdirectory( loopsRefsAuto ) add_subdirectory( memcheck ) add_subdirectory( modern_oo ) diff --git a/exercises/Makefile b/exercises/Makefile index 647e410b..5c7e7613 100644 --- a/exercises/Makefile +++ b/exercises/Makefile @@ -1,18 +1,20 @@ -TESTDIRS = callgrind cppcheck header_units control hello modules move python smartPointers templates virtual_inheritance \ - debug helgrind memcheck polymorphism race stl valgrind basicTypes -NOCOMPILETESTDIRS = constness +TESTDIRS = asan callgrind condition_variable control cppcheck debug functions \ + header_units helgrind hello loopsRefsAuto memcheck modern_oo modules \ + move operators polymorphism python race smartPointers templates \ + valgrind virtual_inheritance +NOCOMPILETESTDIRS = basicTypes constness stl variadic -solution: +all: for dir in ${TESTDIRS}; do \ cd $${dir}; \ make $@; \ cd ..; \ done -clean: +solution clean: for dir in ${TESTDIRS} ${NOCOMPILETESTDIRS}; do \ cd $${dir}; \ - make clean; \ + make $@; \ cd ..; \ done diff --git a/exercises/asan/.gitignore b/exercises/asan/.gitignore new file mode 100644 index 00000000..2283c96d --- /dev/null +++ b/exercises/asan/.gitignore @@ -0,0 +1,2 @@ +asan +asan.sol diff --git a/exercises/basicTypes/.gitignore b/exercises/basicTypes/.gitignore new file mode 100644 index 00000000..c8d7d09f --- /dev/null +++ b/exercises/basicTypes/.gitignore @@ -0,0 +1,2 @@ +basicTypes +basicTypes.sol diff --git a/exercises/callgrind/.gitignore b/exercises/callgrind/.gitignore new file mode 100644 index 00000000..8f9f534d --- /dev/null +++ b/exercises/callgrind/.gitignore @@ -0,0 +1,2 @@ +fibocrunch +fibocrunch.sol diff --git a/exercises/concepts/.gitignore b/exercises/concepts/.gitignore new file mode 100644 index 00000000..19d630b6 --- /dev/null +++ b/exercises/concepts/.gitignore @@ -0,0 +1 @@ +concepts diff --git a/exercises/condition_variable/.gitignore b/exercises/condition_variable/.gitignore new file mode 100644 index 00000000..753f759f --- /dev/null +++ b/exercises/condition_variable/.gitignore @@ -0,0 +1,2 @@ +condition_variable +condition_variable.sol diff --git a/exercises/constness/.gitignore b/exercises/constness/.gitignore new file mode 100644 index 00000000..57abd716 --- /dev/null +++ b/exercises/constness/.gitignore @@ -0,0 +1 @@ +constplay diff --git a/exercises/control/.gitignore b/exercises/control/.gitignore new file mode 100644 index 00000000..3c3b9fe9 --- /dev/null +++ b/exercises/control/.gitignore @@ -0,0 +1,2 @@ +control +control.sol diff --git a/exercises/cppcheck/.gitignore b/exercises/cppcheck/.gitignore new file mode 100644 index 00000000..634133d7 --- /dev/null +++ b/exercises/cppcheck/.gitignore @@ -0,0 +1,2 @@ +randomize +randomize.sol diff --git a/exercises/debug/.gitignore b/exercises/debug/.gitignore new file mode 100644 index 00000000..18ed3421 --- /dev/null +++ b/exercises/debug/.gitignore @@ -0,0 +1,2 @@ +debug +debug.sol diff --git a/exercises/functions/.gitignore b/exercises/functions/.gitignore new file mode 100644 index 00000000..ab406cf6 --- /dev/null +++ b/exercises/functions/.gitignore @@ -0,0 +1,2 @@ +functions +functions.sol diff --git a/exercises/header_units/.gitignore b/exercises/header_units/.gitignore new file mode 100644 index 00000000..10be76d2 --- /dev/null +++ b/exercises/header_units/.gitignore @@ -0,0 +1,3 @@ +header_units +header_units.sol +gcm.cache diff --git a/exercises/helgrind/.gitignore b/exercises/helgrind/.gitignore new file mode 100644 index 00000000..c0308138 --- /dev/null +++ b/exercises/helgrind/.gitignore @@ -0,0 +1,2 @@ +fiboMT +fiboMT.sol diff --git a/exercises/hello/.gitignore b/exercises/hello/.gitignore new file mode 100644 index 00000000..ce013625 --- /dev/null +++ b/exercises/hello/.gitignore @@ -0,0 +1 @@ +hello diff --git a/exercises/loopsRefsAuto/.gitignore b/exercises/loopsRefsAuto/.gitignore new file mode 100644 index 00000000..e757cd3a --- /dev/null +++ b/exercises/loopsRefsAuto/.gitignore @@ -0,0 +1,2 @@ +loopsRefsAuto +loopsRefsAuto.sol diff --git a/exercises/memcheck/.gitignore b/exercises/memcheck/.gitignore new file mode 100644 index 00000000..b543e843 --- /dev/null +++ b/exercises/memcheck/.gitignore @@ -0,0 +1,2 @@ +memleak +memleak.sol diff --git a/exercises/modern_oo/.gitignore b/exercises/modern_oo/.gitignore new file mode 100644 index 00000000..51fcd463 --- /dev/null +++ b/exercises/modern_oo/.gitignore @@ -0,0 +1,2 @@ +particles +particles.sol diff --git a/exercises/modules/.gitignore b/exercises/modules/.gitignore new file mode 100644 index 00000000..00d0a6d1 --- /dev/null +++ b/exercises/modules/.gitignore @@ -0,0 +1,3 @@ +modules +solution/modules +solution/gcm.cache diff --git a/exercises/move/.gitignore b/exercises/move/.gitignore new file mode 100644 index 00000000..a1c69d40 --- /dev/null +++ b/exercises/move/.gitignore @@ -0,0 +1,2 @@ +trymove +trymove.sol diff --git a/exercises/optional/.gitignore b/exercises/optional/.gitignore new file mode 100644 index 00000000..134d9bc3 --- /dev/null +++ b/exercises/optional/.gitignore @@ -0,0 +1 @@ +optional diff --git a/exercises/polymorphism/.gitignore b/exercises/polymorphism/.gitignore new file mode 100644 index 00000000..6b2be516 --- /dev/null +++ b/exercises/polymorphism/.gitignore @@ -0,0 +1,2 @@ +trypoly +trypoly.sol diff --git a/exercises/race/.gitignore b/exercises/race/.gitignore new file mode 100644 index 00000000..76613f70 --- /dev/null +++ b/exercises/race/.gitignore @@ -0,0 +1,3 @@ +racing +racing.sol1 +racing.sol2 diff --git a/exercises/smartPointers/.gitignore b/exercises/smartPointers/.gitignore new file mode 100644 index 00000000..f6bbf861 --- /dev/null +++ b/exercises/smartPointers/.gitignore @@ -0,0 +1,10 @@ +problem1 +problem2 +problem3 +problem4 +problem5 +problem1.sol +problem2.sol +problem3.sol +problem4.sol +problem5.sol diff --git a/exercises/stl/.gitignore b/exercises/stl/.gitignore new file mode 100644 index 00000000..93fdcdf1 --- /dev/null +++ b/exercises/stl/.gitignore @@ -0,0 +1,2 @@ +randomize.nostl +randomize.sol diff --git a/exercises/templates/.gitignore b/exercises/templates/.gitignore new file mode 100644 index 00000000..f36832f3 --- /dev/null +++ b/exercises/templates/.gitignore @@ -0,0 +1,2 @@ +playwithsort +playwithsort.sol diff --git a/exercises/valgrind/.gitignore b/exercises/valgrind/.gitignore new file mode 100644 index 00000000..18ed3421 --- /dev/null +++ b/exercises/valgrind/.gitignore @@ -0,0 +1,2 @@ +debug +debug.sol diff --git a/exercises/variadic/.gitignore b/exercises/variadic/.gitignore new file mode 100644 index 00000000..711c49af --- /dev/null +++ b/exercises/variadic/.gitignore @@ -0,0 +1,2 @@ +variadic +variadic.sol diff --git a/exercises/variant/.gitignore b/exercises/variant/.gitignore new file mode 100644 index 00000000..2e6bf93e --- /dev/null +++ b/exercises/variant/.gitignore @@ -0,0 +1 @@ +variant diff --git a/exercises/virtual_inheritance/.gitignore b/exercises/virtual_inheritance/.gitignore new file mode 100644 index 00000000..a2d52d8f --- /dev/null +++ b/exercises/virtual_inheritance/.gitignore @@ -0,0 +1,2 @@ +trymultiherit +trymultiherit.sol From 3b54c58e5d4616fa4a2bb8405babd7fb40165f27 Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Sun, 9 Mar 2025 21:37:15 +0100 Subject: [PATCH 138/156] updated compiler versions and C++ versions status --- talk/introduction/history.tex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/talk/introduction/history.tex b/talk/introduction/history.tex index feb2219c..fcb02969 100644 --- a/talk/introduction/history.tex +++ b/talk/introduction/history.tex @@ -89,8 +89,8 @@ \begin{itemize} \item A new \cpp specification every 3 years \begin{itemize} - \item \cpp23 complete since 11\textsuperscript{th} of Feb. 2023, awaiting ISO ballot - \item work on \cpp26 has begun + \item \cpp23 complete since 11\textsuperscript{th} of Feb. 2023 + \item work on \cpp26 is ongoing \end{itemize} \item Bringing each time a lot of goodies \end{itemize} @@ -113,8 +113,8 @@ 11 & $\geq$4.8 & $\geq$3.3\\ 14 & $\geq$4.9 & $\geq$3.4\\ 17 & $\geq$7.3 & $\geq$5\\ - 20 & $>$11, 14 & $>$12,18 \\ - 23 & $>$14 & $>$17,18 \\ + 20 & $\geq$11, 14 & $\geq$19 \\ + 23 & $>$15 & $>$20 \\ \end{tabular} \caption{Minimum versions of gcc and clang for a given \cpp version} \end{center} From 5bf6194daf0614e12583c5e9aaaf5e04e94d27d4 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Tue, 11 Mar 2025 14:42:12 +0100 Subject: [PATCH 139/156] Small refinements for objectorientation chapter. --- talk/objectorientation/advancedoo.tex | 3 +-- talk/objectorientation/allocations.tex | 4 ++-- talk/objectorientation/constructors.tex | 31 +++++++++++++++++++++---- talk/objectorientation/operators.tex | 10 ++++---- 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/talk/objectorientation/advancedoo.tex b/talk/objectorientation/advancedoo.tex index a887ca58..420fcd59 100644 --- a/talk/objectorientation/advancedoo.tex +++ b/talk/objectorientation/advancedoo.tex @@ -244,8 +244,7 @@ \frametitlecpp[11]{{\texttt override} keyword} \begin{block}{Principle} \begin{itemize} - \item when overriding a virtual method - \item the \cppinline|override| keyword should be used + \item when overriding a virtual method, the \cppinline|override| keyword should be used \item the \cppinline|virtual| keyword is then optional \end{itemize} \end{block} diff --git a/talk/objectorientation/allocations.tex b/talk/objectorientation/allocations.tex index 8b16db6d..94d267ca 100644 --- a/talk/objectorientation/allocations.tex +++ b/talk/objectorientation/allocations.tex @@ -37,7 +37,7 @@ \item each thread in a process has its own stack \begin{itemize} \item allocations on the stack are thus ``thread private'' - \item and do not introduce any thread safety issues + \item and do not introduce any thread-safety issues \end{itemize} \end{itemize} \end{block} @@ -77,7 +77,7 @@ \item there is a single, shared heap per process \begin{itemize} \item allows to share data between threads - \item introduces race conditions and thread safety issues! + \item introduces race conditions and thread-safety issues! \end{itemize} \end{itemize} \end{block} diff --git a/talk/objectorientation/constructors.tex b/talk/objectorientation/constructors.tex index 6e210f63..ef135640 100644 --- a/talk/objectorientation/constructors.tex +++ b/talk/objectorientation/constructors.tex @@ -106,6 +106,27 @@ \begin{frame}[fragile] \frametitlecpp[98]{Class Constructors and Destructors} + \begin{overprint} + \onslide<1> + \begin{cppcode} + class Vector { + public: + Vector(int n); + Vector(const Vector &other); + ~Vector(); + private: + int len; int* data; + }; + Vector::Vector(int n) : len(n) { + data = new int[n]; + } + + + + + Vector::~Vector() { delete[] data; } + \end{cppcode} + \onslide<2> \begin{cppcode} class Vector { public: @@ -124,6 +145,8 @@ } Vector::~Vector() { delete[] data; } \end{cppcode} + + \end{overprint} \end{frame} \begin{frame}[fragile] @@ -266,8 +289,8 @@ \begin{block}{After object declaration, arguments within \{\}} \begin{cppcode*}{} struct A { - int a; - float b; + int i; + float f; A(); A(int); A(int, int); @@ -287,8 +310,8 @@ \begin{block}{Arguments are given within (), aka \cpp98 nightmare} \begin{cppcode*}{} struct A { - int a; - float b; + int i; + float f; A(); A(int); A(int, int); diff --git a/talk/objectorientation/operators.tex b/talk/objectorientation/operators.tex index 94d11b98..c1d7a00b 100644 --- a/talk/objectorientation/operators.tex +++ b/talk/objectorientation/operators.tex @@ -7,8 +7,8 @@ float m_real, m_imaginary; Complex(float real, float imaginary); Complex operator+(const Complex& other) { - return Complex(m_real + other.m_real, - m_imaginary + other.m_imaginary); + return Complex{m_real + other.m_real, + m_imaginary + other.m_imaginary}; } }; @@ -57,7 +57,7 @@ struct Complex { float m_real, m_imaginary; Complex operator+(float other) { - return Complex(m_real + other, m_imaginary); + return Complex{m_real + other, m_imaginary}; } }; Complex c1{2.f, 3.f}; @@ -67,7 +67,7 @@ \pause \begin{cppcode*}{firstnumber=10} Complex operator+(float a, const Complex& obj) { - return Complex(a + obj.m_real, obj.m_imaginary); + return Complex{a + obj.m_real, obj.m_imaginary}; } \end{cppcode*} \end{block} @@ -102,7 +102,7 @@ \item They gain access to all private/protected members \item Useful for operators such as \cppinline{a + b} \item Don't abuse friends to go around a wrongly designed interface - \item Avoid unexpected modifications of class state in a friend + \item Avoid unexpected modifications of class state in a friend! \end{itemize} \end{block} \begin{exampleblock}{\texttt{operator+} as a friend} From 8ba1a0d8014b602f5853d27e698c6c83c2938469 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Tue, 11 Mar 2025 14:42:38 +0100 Subject: [PATCH 140/156] Add "explicit" keyword for several unary constructors. We recommend to use explicit for unary constructors, but we are not using is in the following slides. Here, it is added in several places where the addition doesn't create space issues on the slide. --- talk/objectorientation/constructors.tex | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/talk/objectorientation/constructors.tex b/talk/objectorientation/constructors.tex index ef135640..ef990ecc 100644 --- a/talk/objectorientation/constructors.tex +++ b/talk/objectorientation/constructors.tex @@ -226,7 +226,7 @@ \begin{cppcode} struct Delegate { int m_i; - Delegate(int i) : m_i(i) { + explicit Delegate(int i) : m_i(i) { ... complex initialization ... } Delegate() : Delegate(42) {} @@ -247,7 +247,7 @@ \begin{exampleblock}{Practically} \begin{cppcode} struct Base { - Base(int a); // ctor 1 + explicit Base(int a); // ctor 1 }; struct Derived : Base { using Base::Base; @@ -270,9 +270,9 @@ \begin{exampleblock}{Practically} \begin{cppcode} struct Base { - int a{5}; // also possible: int a = 5; - Base() = default; - Base(int _a) : a(_a) {} + int a{5}; // or: int a = 5; + Base() = default; + explicit Base(int _a) : a(_a) {} }; struct Derived : Base { int b{6}; From d20e0768446ed8a333a8059710ff90d9fe51537e Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Tue, 11 Mar 2025 14:47:10 +0100 Subject: [PATCH 141/156] Add latex helper files to gitignore. --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 22b9f4ba..c32d5754 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,7 @@ package-lock.json package.json node_modules/** + +# Temporary latex files: +talk/C++Course.* +talk/_minted From 376e6daf71bd9d751ad8b08a8d6228f0e704ff3a Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Wed, 12 Mar 2025 14:48:31 +0100 Subject: [PATCH 142/156] Added missing include in classes exercise --- exercises/classes/classes.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/exercises/classes/classes.cpp b/exercises/classes/classes.cpp index 15e24023..e3cba9fe 100644 --- a/exercises/classes/classes.cpp +++ b/exercises/classes/classes.cpp @@ -1,5 +1,6 @@ #include #include +#include #include class Fraction { From cde47b7b45cbd7f81014d7e3511e444031737f1f Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Wed, 12 Mar 2025 15:53:49 +0100 Subject: [PATCH 143/156] Dropped clang comment on error reporting --- talk/tools/compiling.tex | 1 - 1 file changed, 1 deletion(-) diff --git a/talk/tools/compiling.tex b/talk/tools/compiling.tex index e459ed58..7904da03 100644 --- a/talk/tools/compiling.tex +++ b/talk/tools/compiling.tex @@ -42,7 +42,6 @@ free and open source \item[\href{http://clang.llvm.org/}{\beamergotobutton{clang}}] drop-in replacement of gcc \\ - slightly better error reporting \\ free and open source, based on LLVM \item[\href{https://www.intel.com/content/www/us/en/developer/tools/oneapi/dpc-compiler.html\#gs.dyllp0}{\beamergotobutton{icc} \beamergotobutton{icx}}] Intel's compilers, proprietary but now free \\ From b95492b2d0f1fc9e1badc8f3cf5c6b222205eb41 Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Wed, 12 Mar 2025 16:02:58 +0100 Subject: [PATCH 144/156] Update cmake snipset for c++ standard --- talk/tools/compiling.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/talk/tools/compiling.tex b/talk/tools/compiling.tex index 7904da03..5da7bee7 100644 --- a/talk/tools/compiling.tex +++ b/talk/tools/compiling.tex @@ -181,7 +181,7 @@ find_package(ZLIB REQUIRED) # for external libs add_executable(hello main.cpp util.h util.cpp) - target_compile_features(hello PUBLIC cxx_std_17) + set(CMAKE_CXX_STANDARD 20) target_link_libraries(hello PUBLIC ZLIB::ZLIB) \end{minted} \end{block} From abce4fdad4331b3253b73cbad8eed4fec3f0ee5f Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Wed, 12 Mar 2025 15:51:59 +0100 Subject: [PATCH 145/156] Adding a slide on chaining operators --- talk/objectorientation/operators.tex | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/talk/objectorientation/operators.tex b/talk/objectorientation/operators.tex index c1d7a00b..0ea892b8 100644 --- a/talk/objectorientation/operators.tex +++ b/talk/objectorientation/operators.tex @@ -94,6 +94,28 @@ \end{block} \end{frame} +\begin{frame}[fragile] + \frametitlecpp[98]{Chaining operators} + \begin{block}{In general, return a reference to the left value} + \begin{cppcode} + struct Complex { + float m_real, m_imaginary; + Complex& operator=( const Complex& other ) { + m_real = other.m_real; + m_imaginary = other.m_imaginary; + return *this; + } + }; + Complex c1{2.f, 3.f}; + Complex c2, c3; + // right to left associativity + c3 = c2 = c1; + // left to right associativity + std::cout << c1 << c2 << c3 << std::endl; + \end{cppcode} + \end{block} +\end{frame} + \begin{frame}[fragile] \frametitlecpp[98]{Friend declarations} \begin{block}{Concept} From d4a57dde7a0bc23f28e5c1422457fa1584133aab Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Wed, 12 Mar 2025 15:48:27 +0100 Subject: [PATCH 146/156] Added explanation for usage of CHECK macro in exercises --- exercises/classes/classes.cpp | 4 ++++ exercises/classes/solution/classes_sol.cpp | 4 ++++ exercises/operators/operators.cpp | 4 ++++ exercises/operators/solution/operators_sol.cpp | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/exercises/classes/classes.cpp b/exercises/classes/classes.cpp index e3cba9fe..05bd5dc4 100644 --- a/exercises/classes/classes.cpp +++ b/exercises/classes/classes.cpp @@ -35,6 +35,10 @@ class Fraction { // ADD YOUR CODE HERE +// This is using the cpp, the C preprocessor to expand a bit of code +// (the what argument) to a pair containing a string representation +// of it and the code itself. That way, print is given a string and a +// value where the string is the code that lead to the value #define CHECK(print,what) print(#what, what) unsigned int WIDTH {20}; diff --git a/exercises/classes/solution/classes_sol.cpp b/exercises/classes/solution/classes_sol.cpp index f85f5c9b..7b0f38b5 100644 --- a/exercises/classes/solution/classes_sol.cpp +++ b/exercises/classes/solution/classes_sol.cpp @@ -53,6 +53,10 @@ class TestResultPrinter { }; +// This is using the cpp, the C preprocessor to expand a bit of code +// (the what argument) to a pair containing a string representation +// of it and the code itself. That way, print is given a string and a +// value where the string is the code that lead to the value #define CHECK(printer,what) printer.process(#what, what) int main() { diff --git a/exercises/operators/operators.cpp b/exercises/operators/operators.cpp index caa361c2..625c9c25 100644 --- a/exercises/operators/operators.cpp +++ b/exercises/operators/operators.cpp @@ -58,6 +58,10 @@ class TestResultPrinter { }; +// This is using the cpp, the C preprocessor to expand a bit of code +// (the what argument) to a pair containing a string representation +// of it and the code itself. That way, print is given a string and a +// value where the string is the code that lead to the value #define CHECK(printer,what) printer.process(#what, what) int main() { diff --git a/exercises/operators/solution/operators_sol.cpp b/exercises/operators/solution/operators_sol.cpp index a03fda7e..2ec53056 100644 --- a/exercises/operators/solution/operators_sol.cpp +++ b/exercises/operators/solution/operators_sol.cpp @@ -69,6 +69,10 @@ class TestResultPrinter { }; +// This is using the cpp, the C preprocessor to expand a bit of code +// (the what argument) to a pair containing a string representation +// of it and the code itself. That way, print is given a string and a +// value where the string is the code that lead to the value #define CHECK(printer,what) printer(#what, what) int main() { From 2a28193a7d55adeab77b335e8541cb916984dd74 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Mon, 10 Mar 2025 10:02:24 +0100 Subject: [PATCH 147/156] Label slide as c++11 because we use enum class. --- talk/basicconcepts/classenum.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/talk/basicconcepts/classenum.tex b/talk/basicconcepts/classenum.tex index 6f4ebf33..aabdcc6c 100644 --- a/talk/basicconcepts/classenum.tex +++ b/talk/basicconcepts/classenum.tex @@ -156,7 +156,7 @@ \end{frame} \begin{frame}[fragile] - \frametitlecpp[98]{More sensible example} + \frametitlecpp[11]{More sensible example} \begin{multicols}{2} \begin{cppcode*}{} enum class ShapeType { From efe3f1c2ee22aabde2effa596d7e0bbe57f9ac5a Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Mon, 10 Mar 2025 14:25:43 +0100 Subject: [PATCH 148/156] [basicTypes] Remove confusing statement about operator precedence. The question was about boolean logic, and not precedences. --- exercises/basicTypes/basicTypes.cpp | 2 +- exercises/basicTypes/solution/basicTypes.sol.cpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/exercises/basicTypes/basicTypes.cpp b/exercises/basicTypes/basicTypes.cpp index 3a46116b..b67bccb8 100644 --- a/exercises/basicTypes/basicTypes.cpp +++ b/exercises/basicTypes/basicTypes.cpp @@ -45,7 +45,7 @@ int main() { bool condition1 = false; bool condition2 = true; print( alwaysTrue && condition1 && condition2 ); - print( alwaysTrue || condition1 && condition2 ); // Q: Why does operator precedence render this expression useless? + print( alwaysTrue || condition1 && condition2 ); // Q: Are this and the following expressions useful? print( alwaysTrue && condition1 || condition2 ); print(condition1 != condition1); // Q: What is the difference between this and the following expression? print(condition2 = !condition2); diff --git a/exercises/basicTypes/solution/basicTypes.sol.cpp b/exercises/basicTypes/solution/basicTypes.sol.cpp index f8b94551..047c5d89 100644 --- a/exercises/basicTypes/solution/basicTypes.sol.cpp +++ b/exercises/basicTypes/solution/basicTypes.sol.cpp @@ -45,8 +45,9 @@ int main() { bool condition1 = false; bool condition2 = true; print( alwaysTrue && condition1 && condition2 ); - print( alwaysTrue || condition1 && condition2 ); // Q: Why does operator precedence render this expression useless? - print( alwaysTrue && condition1 || condition2 ); // A: "true || " is evaluated last. The expression therefore is always true. + print( alwaysTrue || condition1 && condition2 ); // Q: Are this and the following expressions useful? + // A: Not really. Since we use "true ||", it is always true. + print( alwaysTrue && condition1 || condition2 ); // A: "true && condition1" is the same as "condition1" print(condition1 != condition1); // Q: What is the difference between this and the following expression? print(condition2 = !condition2); // A: The first is a comparison, the second a negation with subsequent assignment print( alwaysTrue && condition1 && condition2 ); From b411bd8ea0fdd45889dd705f6f21cf47ed34ee64 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Mon, 10 Mar 2025 14:31:57 +0100 Subject: [PATCH 149/156] [basicTypes] Prefix binary representation with 0b. Thanks to Oliver for this idea! --- exercises/basicTypes/PrintHelper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/basicTypes/PrintHelper.h b/exercises/basicTypes/PrintHelper.h index 073729bc..50b25166 100644 --- a/exercises/basicTypes/PrintHelper.h +++ b/exercises/basicTypes/PrintHelper.h @@ -22,7 +22,7 @@ void printWithTypeInfo(std::string expression, auto const & t, bool useBitset = std::cout << std::left << std::setw(30) << expression << " type=" << std::setw(20) << realname << "value="; if (useBitset) { - std::cout << std::bitset<16>(t) << "\n"; + std::cout << "0b" << std::bitset<16>(t) << "\n"; } else { std::cout << std::setprecision(25) << t << "\n"; } From 89f4620d0e9e760c25ced549531d2ab53e933321 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Mon, 10 Mar 2025 15:56:11 +0100 Subject: [PATCH 150/156] [loopsRefsAuto] Clarify a task. --- exercises/loopsRefsAuto/loopsRefsAuto.cpp | 3 ++- exercises/loopsRefsAuto/solution/loopsRefsAuto.sol.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/exercises/loopsRefsAuto/loopsRefsAuto.cpp b/exercises/loopsRefsAuto/loopsRefsAuto.cpp index bc0e5ced..0cb63fa4 100644 --- a/exercises/loopsRefsAuto/loopsRefsAuto.cpp +++ b/exercises/loopsRefsAuto/loopsRefsAuto.cpp @@ -17,7 +17,8 @@ int main() { DontCopyMe collection[10]; // Task 1: - // Write a for loop that initialises each struct's resultA and resultB with ascending integers. + // Write a for loop that initialises resultA and resultB for each element in the above array + // with sensible numbers. // Verify the output of the program before and after you do this. diff --git a/exercises/loopsRefsAuto/solution/loopsRefsAuto.sol.cpp b/exercises/loopsRefsAuto/solution/loopsRefsAuto.sol.cpp index df04f05c..b248f843 100644 --- a/exercises/loopsRefsAuto/solution/loopsRefsAuto.sol.cpp +++ b/exercises/loopsRefsAuto/solution/loopsRefsAuto.sol.cpp @@ -17,7 +17,8 @@ int main() { DontCopyMe collection[10]; // Task 1: - // Write a for loop that initialises each struct's resultA and resultB with ascending integers. + // Write a for loop that initialises resultA and resultB for each element in the above array + // with sensible numbers. // Verify the output of the program before and after you do this. for ( int i = 0 ; i<10 ; ++i ) { From 69cac60c33013f484eef007112bd237c5a053cac Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Wed, 12 Mar 2025 16:46:23 +0100 Subject: [PATCH 151/156] [basicTypes] Clarify that PrintHelper.h is not part of the exercise. --- exercises/basicTypes/PrintHelper.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/exercises/basicTypes/PrintHelper.h b/exercises/basicTypes/PrintHelper.h index 50b25166..7df4c126 100644 --- a/exercises/basicTypes/PrintHelper.h +++ b/exercises/basicTypes/PrintHelper.h @@ -5,6 +5,12 @@ #include #include +/* + * NOTE: You don't need to understand the print helpers here. + * Their purpose is to show each expression, the type it evaluates to, and the value it evaluates to. + * Please go back to the main file now. :-) + */ + #ifdef _MSC_VER std::string demangle(std::string_view input) { return std::string{input}; } #else From da133a04282d310eb5507c8d3fb952cfc4d691ee Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 14 Mar 2025 11:00:17 +0100 Subject: [PATCH 152/156] [templates] Convert warning box to notes. The warning box was perceived as too strong. We don't want to discourage people from templates. --- talk/morelanguage/templates.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/talk/morelanguage/templates.tex b/talk/morelanguage/templates.tex index e212564b..81c132a4 100644 --- a/talk/morelanguage/templates.tex +++ b/talk/morelanguage/templates.tex @@ -28,7 +28,7 @@ \begin{frame}[fragile] \frametitlecpp[98]{Templates} - \begin{alertblock}{Warning} + \begin{block}{Notes on templates} \begin{itemize} \item they are compiled for each instantiation \item they need to be defined before used @@ -38,7 +38,7 @@ \end{itemize} \item this may lead to longer compilation times and bigger binaries \end{itemize} - \end{alertblock} + \end{block} \newsavebox{\codepiece} \begin{lrbox}{\codepiece} \begin{minipage}{.35\linewidth} From 42535175a2fa5375b98cfc0dd251c8f7b82095f5 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 14 Mar 2025 11:50:49 +0100 Subject: [PATCH 153/156] Mark a structured binding as C++17. --- talk/morelanguage/stl.tex | 1 + 1 file changed, 1 insertion(+) diff --git a/talk/morelanguage/stl.tex b/talk/morelanguage/stl.tex index fb1b3ccc..ea8a3af4 100644 --- a/talk/morelanguage/stl.tex +++ b/talk/morelanguage/stl.tex @@ -133,6 +133,7 @@ m["hello"] = 1; // inserts new key, def. constr. value m["hello"] = 2; // finds existing key auto [it, isNewKey] = m.insert({"hello", 0}); // no effect + // ^ C++17: "Structured binding" int val = m["world"]; // inserts new key (val == 0) int val = m.at("monde"); // throws std::out_of_range From 34855512d5aceb36e68dfe3d31a21a11e8bdb5cc Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 14 Mar 2025 11:51:24 +0100 Subject: [PATCH 154/156] [NFC] Typography --- talk/morelanguage/lambda.tex | 2 +- talk/morelanguage/raii.tex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/talk/morelanguage/lambda.tex b/talk/morelanguage/lambda.tex index c9e7309c..3d32c11a 100644 --- a/talk/morelanguage/lambda.tex +++ b/talk/morelanguage/lambda.tex @@ -211,7 +211,7 @@ \end{column} \end{columns} \end{block} - \begin{exampleblock}{Some nice consequence} + \begin{exampleblock}{Some nice consequences} \begin{itemize} \item Lambda expressions create ordinary objects \item They can be copied, moved, or inherited from diff --git a/talk/morelanguage/raii.tex b/talk/morelanguage/raii.tex index 710a6be2..b895fe07 100644 --- a/talk/morelanguage/raii.tex +++ b/talk/morelanguage/raii.tex @@ -277,7 +277,7 @@ \begin{frame}[fragile] \frametitlecpp[11]{\texttt{std::shared\_ptr}} - \begin{block}{\mintinline{cpp}{std::shared_ptr} : a reference counting pointer} + \begin{block}{\mintinline{cpp}{std::shared_ptr} : a reference-counting pointer} \begin{itemize} \item wraps a regular pointer similar to \cppinline{unique_ptr} \item has move and copy semantic From 8f9cbfbc33ebbe4599d96ef7e255351558e885c6 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 14 Mar 2025 12:10:39 +0100 Subject: [PATCH 155/156] Extend lambda slides with init captures and comparison of val vs ref. --- talk/morelanguage/lambda.tex | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/talk/morelanguage/lambda.tex b/talk/morelanguage/lambda.tex index 3d32c11a..7c064e4e 100644 --- a/talk/morelanguage/lambda.tex +++ b/talk/morelanguage/lambda.tex @@ -169,6 +169,36 @@ \end{exampleblock} \end{frame} +\begin{frame}[fragile] + \frametitlecpp[11]{Capture by value vs.\ by reference} + \begin{exampleblock}{See the difference between val and ref} + \begin{cppcode*}{} + int data[]{1,9,3,8,3,7,4,6,5}; + int increment = 3; + auto val = [ inc](int x) { return x+inc; }; + auto ref = [&inc](int x) { return x+inc; }; + + increment = 4; + + for(int& i : data) i = val(i); // increments by 3 + for(int& i : data) i = ref(i); // increments by 4 + \end{cppcode*} + \end{exampleblock} +\end{frame} + +\begin{frame}[fragile] + \frametitlecpp[14]{Init capture} + \begin{exampleblock}{Capture with an initializer} + In \cpp14, can declare captures with initializers + \begin{cppcode*}{} + auto f = [inc = 1+2](int x) { return x+inc; }; + auto g = [inc = getInc()](int x) { return x+inc; }; + for(int& i : data) i = f(i); // increments by 3 + for(int& i : data) i = g(i); // unknown increment + \end{cppcode*} + \end{exampleblock} +\end{frame} + \begin{frame}[fragile] \frametitlecpp[11]{Anatomy of a lambda} \begin{block}{Lambdas are pure syntactic sugar - \cppinsightLink{https://cppinsights.io/s/67800da8}} From 20c735b86f594b85735fd3c65e3c202fced585da Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Fri, 14 Mar 2025 16:45:10 +0100 Subject: [PATCH 156/156] Fixed slide on noexcept --- talk/morelanguage/exceptions.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/talk/morelanguage/exceptions.tex b/talk/morelanguage/exceptions.tex index 6a608db5..77a08686 100644 --- a/talk/morelanguage/exceptions.tex +++ b/talk/morelanguage/exceptions.tex @@ -319,7 +319,7 @@ \end{cppcode*} \begin{itemize} \item either no exceptions is thrown or they are handled internally - \item checked at compile time + \item if one is thrown, `std::terminate` is called \item allows the compiler to optimize around that knowledge \end{itemize} \item a function with \cppinline{noexcept(expression)} is only \cppinline{noexcept} when \cppinline{expression} evaluates to \cppinline{true} at compile-time pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy