We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← RAII: Objects With Lifetimes step 2 of 4
Write the guard yourself
A scope guard pairs an action at construction with cleanup at destruction. Complete a small guard that increments a counter when it is created and decrements the same counter when it goes out of scope.
This is an example of RAII: tying resource management to object lifetime.
Standard types such as std::lock_guard and std::unique_ptr use this idea,
though their interfaces and ownership rules differ.
One acquisition, one release
CounterGuard stores a reference to a Counter. Its constructor calls
acquire() once; its destructor calls release() once. The counter must
outlive every guard referring to it. The supplied calls keep that lifetime
relationship intact.
Each recursive call in nest creates one guard before calling itself again.
The earlier guards stay alive during that call. As the calls return, the
guards are destroyed in reverse order and the live count falls back to zero.
Destructors also clean up fully constructed local guards during ordinary exception unwinding. This does not promise cleanup after every kind of process termination, or destruction of an object whose constructor failed.
Prevent accidental copies
A compiler-generated copy constructor would copy the reference without calling
acquire() again. Two guards would then release a counter that was acquired
only once. For this guard, prevent copying explicitly:
CounterGuard(const CounterGuard&) = delete;
CounterGuard& operator=(const CounterGuard&) = delete;
The reference member already prevents generated copy assignment, but the explicit deletion documents the class's intended interface. No move operations are needed for this exercise. With these declarations and a destructor, none are generated automatically.
This is a choice for this scope guard, not a rule that every resource-managing class must forbid copying. Other classes can define safe copying or shared ownership with different semantics.
Keep the constructor explicit. It permits direct construction such as
CounterGuard guard{counter} while preventing an implicit conversion from
Counter& to a guard, which would change the live count as a side effect.
Your task
Complete only CounterGuard. Keep the supplied Counter, nest and
max_live implementations.
int max_live(Counter& counter, const std::vector<int>& depths);
For each positive depth d, the supplied recursion creates d simultaneously
live guards, then destroys them all before processing the next depth. Zero or
negative depths create none. Depths are small enough for this recursive exercise;
it is not a technique for arbitrarily deep input.
Counter::acquire() updates the current live count and its historical peak.
The harness starts with a fresh counter, calls max_live, and reports
[peak, live_afterwards]. For {1, 3, 2}, that is [3, 0], not [6, 0]:
the depths are processed separately. Empty input and all nonpositive depths
produce [0, 0].
The final zero checks for unreleased guards. These output checks do not copy a guard, so passing them alone does not establish the required noncopyable interface. Complete the deleted copy declarations as well as the constructor and destructor.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
C++ reference solution
Sign in to track your attempts toward unlocking the reference solution.