Challenge 3: Why a Destructor-Only Class Still Copies Instead of Moving — Possible Solution ==================================================================== Per this chapter's own suppression table, declaring a destructor (and nothing else) has two DIFFERENT effects on the remaining four special member functions, not one uniform effect: 1. It SUPPRESSES the move constructor and move assignment operator from being auto-generated at all -- neither one exists for this class, full stop, not even as a "bad" or unexpected default. 2. It DOES NOT suppress the copy constructor and copy assignment operator -- both are STILL auto-generated, per the table's own note that this is a deprecated, legacy-compatibility behavior still technically permitted by the standard. When a Widget is passed by value (or `std::move`d, or otherwise put in a context where the compiler needs to construct a new Widget FROM an existing one), overload resolution looks for the best available constructor to use. Because the move constructor doesn't exist at all for this class (per point 1), it can never be selected -- there is simply no candidate matching that description in the overload set. The copy constructor, however, DOES exist (per point 2), and is a perfectly viable candidate for constructing a new Widget from an existing one -- so it gets selected instead, REGARDLESS of whether the source expression was cast to an rvalue via std::move or not. The explicit std::move only affects which OVERLOAD would be preferred IF a matching move overload existed; it cannot conjure one into existence if the class's own declarations suppressed it. This is exactly why a destructor-only class still copies rather than moving: the move path was never a genuine option for it in the first place, so falling back to the copy constructor isn't a bug or a misunderstanding of std::move -- it's the only constructor actually available, chosen correctly by ordinary overload resolution given what that specific class declared. WHY THIS WORKS AS AN ANSWER ------------------------------ This traces the outcome to the table's own two SEPARATE effects (move suppressed entirely; copy still generated, deprecated) rather than treating "the destructor breaks moving" as one vague fact, and explains precisely why std::move's cast is powerless to summon a move constructor that was never generated for this class at all.