diff --git a/hints/02_functions/functions2.md b/hints/02_functions/functions2.md new file mode 100644 index 0000000..7d25f98 --- /dev/null +++ b/hints/02_functions/functions2.md @@ -0,0 +1,5 @@ +# Hint + +A function parameter needs both a type and a name. `callme(x)` declares `x` +with no type, which is not valid C++. `x` is later compared against `int i` and +used as a loop bound, so give it the matching type. diff --git a/hints/02_functions/functions3.md b/hints/02_functions/functions3.md new file mode 100644 index 0000000..2a50681 --- /dev/null +++ b/hints/02_functions/functions3.md @@ -0,0 +1,4 @@ +# Hint + +`callme` is declared to take one argument, but it is called with none. Look at +its signature and pass the value it expects. diff --git a/hints/02_functions/functions4.md b/hints/02_functions/functions4.md new file mode 100644 index 0000000..9421dda --- /dev/null +++ b/hints/02_functions/functions4.md @@ -0,0 +1,5 @@ +# Hint + +`sale_price` is declared to return `void`, yet its body uses `return price - 10;`. +A function that hands a value back to its caller must declare a return type that +matches the value. Look at what the test expects `function_syntax()` to return. diff --git a/hints/02_functions/functions5.md b/hints/02_functions/functions5.md new file mode 100644 index 0000000..63e672d --- /dev/null +++ b/hints/02_functions/functions5.md @@ -0,0 +1,8 @@ +# Hint + +Two things are broken: + +- `is_even` is declared `constexpr void` but returns a `bool`. Give it the + return type that matches the value it computes. +- The lambda takes no parameters (`[]()`) yet its body uses `price`. A lambda + needs its inputs declared in the parameter list, just like a normal function. diff --git a/hints/02_functions/functions6.md b/hints/02_functions/functions6.md new file mode 100644 index 0000000..60ac950 --- /dev/null +++ b/hints/02_functions/functions6.md @@ -0,0 +1,11 @@ +# Hint + +The return line must add three separate values, but the placeholders are empty. +Look at each scope in play: + +- the global `value` (reachable with `::value`) +- the value returned by `called(10)`, stored in the local `value` +- the one inside `my_namespace_0` (reachable with `my_namespace_0::value`) + +The expected total is `13`. Work out which value lives in which scope and add +the three named references together. diff --git a/hints/03_if/if1.md b/hints/03_if/if1.md new file mode 100644 index 0000000..cdd2b3d --- /dev/null +++ b/hints/03_if/if1.md @@ -0,0 +1,11 @@ +# Hint + +The function body is empty, so nothing is returned. The constraints rule out +extra variables and helper calls, which points at the conditional (ternary) +operator: + +``` +condition ? value_if_true : value_if_false +``` + +Return that single expression, comparing `a` and `b`. diff --git a/hints/03_if/if2.md b/hints/03_if/if2.md new file mode 100644 index 0000000..7873446 --- /dev/null +++ b/hints/03_if/if2.md @@ -0,0 +1,13 @@ +# Hint + +Two problems. First, the function can reach its end without returning a value: +every path through the `if` chain must `return` a `std::string`. + +Look at the test cases at the bottom for the expected mapping: + +- `"fizz"` returns `"foo"` +- `"fuzz"` returns `"bar"` +- anything else returns `"baz"` + +Add an `else if` for the `"fuzz"` case and a final `else` (or a trailing +`return`) for the default. diff --git a/hints/04_pointers_references/pointers_references1.md b/hints/04_pointers_references/pointers_references1.md new file mode 100644 index 0000000..8f5762c --- /dev/null +++ b/hints/04_pointers_references/pointers_references1.md @@ -0,0 +1,9 @@ +# Hint + +`my_pointer_value_swap` receives an `int*` but stores it in an `int`. The local +`new_data` must have the same type as what it holds and what the function +returns: a pointer. Fix its type so it can carry the address through. + +`my_pointer_content` takes `int * const value`: the pointer itself is const, so +you cannot move where it points. To change the pointed-to number, work through +the dereferenced value (`*value`) rather than the pointer. diff --git a/hints/04_pointers_references/pointers_references2.md b/hints/04_pointers_references/pointers_references2.md new file mode 100644 index 0000000..3a76c48 --- /dev/null +++ b/hints/04_pointers_references/pointers_references2.md @@ -0,0 +1,8 @@ +# Hint + +The test expects the caller's value to change after `my_reference_content` +returns, but the parameter is passed by value, so the function only edits a +local copy. Line 14 must stay as-is. + +Change the parameter that should be modified so it is a reference (`int&`) +instead of a copy. A reference is an alias for the caller's variable. diff --git a/hints/05_classes/classes1.md b/hints/05_classes/classes1.md new file mode 100644 index 0000000..b7c538a --- /dev/null +++ b/hints/05_classes/classes1.md @@ -0,0 +1,9 @@ +# Hint + +`Bird` and `Cat` inherit `number_legs` and `has_fur` from `Animal`, so they +should set those inherited members, not declare new ones that shadow them. + +- In the `Bird` constructor, `number_legs = ;` is missing its value. A bird has + two legs. +- `Cat` re-declares `has_fur` (line 41). Delete that duplicate so the + constructor writes the inherited member instead of a new shadowing one. diff --git a/hints/05_classes/classes2.md b/hints/05_classes/classes2.md new file mode 100644 index 0000000..3e87ec4 --- /dev/null +++ b/hints/05_classes/classes2.md @@ -0,0 +1,10 @@ +# Hint + +Several holes to fill in this one: + +- `operator==` compares two points. Mirror the `x` comparison for `y`: take the + absolute difference and check it is below the tolerance `1e-6`. +- `point_zero` is a `Point`, so it needs a brace-initialised value for its two + coordinates. + +Look at how the `x` half of the comparison is written and follow the same shape. diff --git a/hints/05_classes/classes3.md b/hints/05_classes/classes3.md new file mode 100644 index 0000000..0f43257 --- /dev/null +++ b/hints/05_classes/classes3.md @@ -0,0 +1,9 @@ +# Hint + +`Circle` derives from `Shape`, but `Shape` has no default constructor that runs +on its own here: the base part must be initialised explicitly. A derived +constructor forwards to its base in the member-initialiser list, before the +body runs. + +Look up "constructor initializer list" and how a derived class calls its base +constructor, then pass the incoming centre through to `Shape`. diff --git a/hints/05_classes/classes4.md b/hints/05_classes/classes4.md new file mode 100644 index 0000000..ff5d716 --- /dev/null +++ b/hints/05_classes/classes4.md @@ -0,0 +1,9 @@ +# Hint + +Virtual dispatch (the vtable) only happens through a reference or a pointer to +the base class, never through a by-value copy. Slicing a `Circle` into a +`Shape` value loses the derived behaviour. + +`shape_collection` holds `Shape*`, so every element must be an address, and +each element is accessed as a pointer. Fix the type or the way the elements are +stored and dereferenced so the calls go through the vtable. diff --git a/hints/06_raii/raii1.md b/hints/06_raii/raii1.md new file mode 100644 index 0000000..05e719d --- /dev/null +++ b/hints/06_raii/raii1.md @@ -0,0 +1,9 @@ +# Hint + +RAII means a resource acquired in the constructor is released in the +destructor. `Holder` allocates an `ExpensiveResource` with `new`, so its +destructor must `delete` it, otherwise the count never returns to zero +(a leak, CWE-401). + +The destructor is declared but has no name or body. Give it the class name +(`~Holder`) and release the resource inside it. diff --git a/hints/06_raii/raii2.md b/hints/06_raii/raii2.md new file mode 100644 index 0000000..dc60e9f --- /dev/null +++ b/hints/06_raii/raii2.md @@ -0,0 +1,9 @@ +# Hint + +Here the resource count is tracked by an `std::unordered_set` keyed on the +resource name. The constructor should register the resource and the +destructor should remove it. + +Look at the two `resources. ...;` lines: the constructor needs `insert` +(add the name) and the destructor needs `erase` (remove it). Because a set +holds each key only once, opening the same name twice does not grow the count. diff --git a/hints/07_containers/containers1.md b/hints/07_containers/containers1.md new file mode 100644 index 0000000..6ba335a --- /dev/null +++ b/hints/07_containers/containers1.md @@ -0,0 +1,8 @@ +# Hint + +A raw C array `int my_sequence[num_elements]` has no `.size()` member and no +`.begin()/.end()`, which is why the test does not compile. + +Replace it with the STL container that is a fixed-size array but knows its own +size: `std::array`. The rest of the code (indexing and the +range-based for loop) then works unchanged. diff --git a/hints/07_containers/containers2.md b/hints/07_containers/containers2.md new file mode 100644 index 0000000..08c5c97 --- /dev/null +++ b/hints/07_containers/containers2.md @@ -0,0 +1,7 @@ +# Hint + +The test inserts the same value `42` several times but expects the final size +to be `1`: duplicates must collapse into a single element. + +That is the job of a set. Look at `std::unordered_set` (or `std::set`) +and use its `insert` member instead of index assignment. diff --git a/hints/07_containers/containers3.md b/hints/07_containers/containers3.md new file mode 100644 index 0000000..bc8153a --- /dev/null +++ b/hints/07_containers/containers3.md @@ -0,0 +1,8 @@ +# Hint + +The code assigns at sparse, non-contiguous indices (0, 50, 100, 150, 200) and +then iterates only over the elements that were actually set. A plain array or +`std::vector` would need every slot up to 200. + +A key-to-value associative container fits: look at `std::map` (or +`std::unordered_map`). Its header is what belongs in the `#include ` line. diff --git a/hints/08_ownership/ownership1.md b/hints/08_ownership/ownership1.md new file mode 100644 index 0000000..69eeb5a --- /dev/null +++ b/hints/08_ownership/ownership1.md @@ -0,0 +1,9 @@ +# Hint + +`fill_vec` takes its vector **by value**, so it modifies a copy and the caller's +`vec` never sees the three `push_back`s. The test expects the original to grow +to 5 elements. + +Following the ownership conventions in the chapter README, borrowing a variable +to modify it in place is done with a reference: change the parameter type so +`fill_vec` operates on the caller's vector directly. diff --git a/hints/08_ownership/ownership2.md b/hints/08_ownership/ownership2.md new file mode 100644 index 0000000..f831b96 --- /dev/null +++ b/hints/08_ownership/ownership2.md @@ -0,0 +1,9 @@ +# Hint + +The goal is to *transfer* ownership of the data out of `vec0` into `vec1`, +leaving `vec0` empty (the test requires `vec0.size() == 0`). + +`fill_vec` takes an rvalue reference (`std::vector&&`), so it wants +something it is allowed to steal from. Look up `std::move`: it casts an lvalue +to an rvalue so its contents can be moved rather than copied. The two `...?` +holes each need the value to be moved. diff --git a/hints/08_ownership/ownership3.md b/hints/08_ownership/ownership3.md new file mode 100644 index 0000000..3ce2f46 --- /dev/null +++ b/hints/08_ownership/ownership3.md @@ -0,0 +1,8 @@ +# Hint + +`holder_list` holds `std::unique_ptr` (a `HolderBox`), and a +`unique_ptr` cannot be copied, only moved. `push_data` receives `hold_ptr` by +value, so it already owns a `unique_ptr` it must hand into the vector. + +Look up `std::move`: `push_back` needs the argument moved in, not copied. +Changing only that one line makes it compile. diff --git a/hints/08_ownership/ownership4.md b/hints/08_ownership/ownership4.md new file mode 100644 index 0000000..b457297 --- /dev/null +++ b/hints/08_ownership/ownership4.md @@ -0,0 +1,9 @@ +# Hint + +`HolderBox` is a raw `Holder*`, and `&h` takes the address of a local that is +destroyed at the end of each loop iteration, so the vector ends up full of +dangling pointers (CWE-416: Use After Free). + +Redefine `HolderBox` as a `std::unique_ptr` so the vector owns each +`Holder`, and create it with `std::make_unique(s)` instead of `&h`. +The owning pointer keeps the resource alive and releases it exactly once. diff --git a/hints/08_ownership/ownership5.md b/hints/08_ownership/ownership5.md new file mode 100644 index 0000000..997aaf9 --- /dev/null +++ b/hints/08_ownership/ownership5.md @@ -0,0 +1,8 @@ +# Hint + +`fill_vec` uses `vec->push_back(...)`, so it expects a pointer, not a value. +Change its parameter type to a raw pointer `std::vector*` so it borrows +the vector without owning it (it must not delete it). + +`vec` is a `std::unique_ptr`. Look up the member that hands out the raw +underlying pointer without giving up ownership, and pass that to `fill_vec`. diff --git a/hints/08_ownership/ownership6.md b/hints/08_ownership/ownership6.md new file mode 100644 index 0000000..3ec7e4d --- /dev/null +++ b/hints/08_ownership/ownership6.md @@ -0,0 +1,10 @@ +# Hint + +`std::shared_ptr` lets several owners share the same data; `use_count()` +reports how many owners currently exist. The exercise wants an extra +"artificial" owner so the count rises. + +The line marked TODO already constructs a second `shared_ptr` from the +argument. Let the compiler deduce the type instead of spelling it out: replace +the explicit datatype so the copy still shares ownership of the same block. +Copying a `shared_ptr` (not moving it) is what bumps `use_count()`. diff --git a/hints/09_templates/templates1.md b/hints/09_templates/templates1.md new file mode 100644 index 0000000..69787ef --- /dev/null +++ b/hints/09_templates/templates1.md @@ -0,0 +1,8 @@ +# Hint + +`max` currently only accepts `int`. To let the same function work for both +`int` and `double`, turn it into a function template. + +Put `template` in front of the function and replace the concrete +`int` types (parameters and return) with `T`. The compiler then stamps out one +version per type you call it with. diff --git a/hints/09_templates/templates2.md b/hints/09_templates/templates2.md new file mode 100644 index 0000000..da262dd --- /dev/null +++ b/hints/09_templates/templates2.md @@ -0,0 +1,8 @@ +# Hint + +`max` only takes a `std::vector`. Make it a template so it also accepts a +`std::vector`. + +Template the element type: `template` and take a +`const std::vector&`. The local maximum and the return type should be `T` +too, so nothing is truncated back to `int`. diff --git a/hints/09_templates/templates3.md b/hints/09_templates/templates3.md new file mode 100644 index 0000000..ebc0c37 --- /dev/null +++ b/hints/09_templates/templates3.md @@ -0,0 +1,9 @@ +# Hint + +Now the container itself varies: a `std::vector` and a +`std::deque`. One template type parameter for the element is not +enough. + +Template on the whole container type instead, e.g. `template` +taking `const Container&`. Return `auto` so the element type is deduced from +whatever the container holds. diff --git a/hints/09_templates/templates4.md b/hints/09_templates/templates4.md new file mode 100644 index 0000000..a56c113 --- /dev/null +++ b/hints/09_templates/templates4.md @@ -0,0 +1,10 @@ +# Hint + +The `?` placeholders are the template parameter. Replace `typename ?` with a +real type parameter name (e.g. `typename T`) on both `Animal` and `Cat`, and use +that name where the `?` and `int` members appear. + +`Cat` derives from `Animal`, so it must forward its type argument to the base: +`Cat : public Animal` and `Animal(years)` in the constructor. Class +template argument deduction then lets `Cat blue(4)` deduce the type from the +constructor argument. diff --git a/hints/09_templates/templates6.md b/hints/09_templates/templates6.md new file mode 100644 index 0000000..c90eb49 --- /dev/null +++ b/hints/09_templates/templates6.md @@ -0,0 +1,15 @@ +# Hint + +`is_string` is already written for you: a primary template inheriting from +`false_type`, plus a full specialization for `std::string` inheriting from +`true_type`. Follow the exact same pattern to define `is_vector`. + +The difference is that a vector is itself a template, so the "true" case is a +partial specialization that keeps the element type generic: + +```cpp +template struct is_vector : false_type {}; +``` + +Add the partial specialization that matches `std::vector` for any `T`. +`is_pointer` in the next exercise follows the same idea for `T*`. diff --git a/hints/09_templates/templates7.md b/hints/09_templates/templates7.md new file mode 100644 index 0000000..b732c21 --- /dev/null +++ b/hints/09_templates/templates7.md @@ -0,0 +1,9 @@ +# Hint + +`is_pointer` from the previous exercise gives a compile-time `::value` that +is true when `T` is a pointer. `if constexpr` picks a branch at compile time +based on that value, so the discarded branch does not even need to be valid for +the other type. + +Put the trait check inside the `if constexpr ( ... )` condition. Remember the +type of the argument is the template parameter `C`.