Code-Tracing — Answers¶
Every output below was produced by compiling and running the snippet with the course
flags (g++ -std=c++17 -Wall -Wextra -Werror), not recalled. Trailing spaces are shown
explicitly where they matter.
T1 — 2 1
Each Counter object has its own value_. a was incremented twice and b once, so
a.value() is 2 and b.value() is 1.
T2 — E+ C+ C- E-
Members are constructed before the constructor body runs, in declaration order, so
engine_ is built first (E+) and then the constructor body prints C+. plate_ is a
std::string and prints nothing. Destruction runs in the reverse order: the class
destructor body prints C-, then engine_'s destructor prints E-.
T3 — 5 6
The trap: initialisation follows declaration order, not the order written in the
initialiser list. a_ is declared first, so a_ is initialised to 5 first, and then
b_ is initialised with a_ + 1 = 6. Had the order been reversed, b_ would have read
an uninitialised a_. GCC warns about the mismatch with -Wreorder.
T4 — 123 3
next_ is one variable shared by the class. The constructor pre-increments it, so a, b
and c receive 1, 2, 3; after all three, next_ is 3. Printing the three n_
values with no separators gives 123, then Id::count() gives 3.
T5 — 7 1 0
a + b builds a temporary with v_ = 7. (a < b) is 2 < 5, true, and std::cout prints
bool as 1; (b < a) prints 0. Note (a < b) needs the parentheses only for
readability — < binds tighter than <<.
T6 — derived base
Base& r = d; binds a reference to the Derived object, so the virtual call dispatches to
Derived::who and prints derived. Base b = d; copies by value, which slices the
object to its Base part, so b.who() calls Base::who and prints base. This pair is
the whole lesson: virtual dispatch works through references and pointers, never through a
sliced value.
T7 — ...
std::vector<Animal> stores Animal values. push_back(Dog{}) copies the Dog into the
Animal slot, slicing off the derived part. speak() therefore calls Animal::speak and
prints .... Fix it with std::vector<std::unique_ptr<Animal>> and push_back(std::make_unique<Dog>()).
T8 — copy 1 9
The user-defined copy constructor prints copy and takes a deep copy, so a and b
point at different arrays. Writing 9 through b.at0() leaves a's data at 1. Printing
a.at0() then b.at0() gives 1 9, after the copy from construction. (With the
compiler-generated shallow copy, b's destructor would delete[] a pointer a still
uses — a double free.)
T9 — mv b7 a-1 close7
H b = std::move(a) calls the move constructor: it prints mv and sets a's id to -1.
b.id() is 7 and a.id() is -1, giving b7 a-1. On scope exit destruction is in
reverse order: b has id 7, so it prints close7; a now has id -1, so it prints
nothing. The -1 is the "moved-from" marker that stops the source releasing a resource the
target now owns.
T10 — logic end
The type thrown is std::out_of_range, and the class hierarchy is
out_of_range : logic_error : exception. A handler catches the thrown type and
everything derived from it, so the inner catch (const std::logic_error&) matches, prints
logic, and the outer catch (const std::exception&) never runs. Only end follows, from
the statement after the outer try. The lesson: when several handlers could match, write
them most-derived first — and do not assume a base-class handler is "too general" to fire.
T11 — 13 3
After std::sort the vector is {1, 2, 2, 3}, so front() is 1 and back() is 3,
printed adjacent as 13. The predicate x > 1 is true for the two 2s and the 3, so
count_if returns 3.
T12 — 11 100
[base] captures by value, copying base into the closure when the lambda was created.
Reassigning base = 100 afterwards does not touch that copy, so add(1) is 10 + 1 = 11.
The main variable prints its new value, 100. Capturing by value is how you freeze a
value; [&base] would have produced 101 100.
Scoring. Twelve questions. Score the whole line's output, ignoring trailing spaces. See Marking Yourself to turn a raw score into a study decision.