Step 7 of 7
Challenge: a move-aware log
One last tool. std::exchange(obj, new_value) from <utility> sets obj to new_value and returns the old value, moving where it can. It's the tidy way to "take" something and leave a reset value behind, in one line.
#include <iostream>
#include <string>
#include <utility>
#include <vector>
class Cart {
public:
void add(std::string item) {
if (item.empty()) return;
items_.push_back(std::move(item)); // sink: move into storage
}
std::vector<std::string> checkout() {
return std::exchange(items_, {}); // hand over, leave an empty cart
}
int size() const { return (int)items_.size(); }
private:
std::vector<std::string> items_;
};
int main() {
Cart cart;
cart.add("milk");
cart.add("");
cart.add("bread");
std::cout << cart.size() << " in cart\n";
std::vector<std::string> bought = cart.checkout();
std::cout << bought.size() << " bought, " << cart.size() << " left\n";
int ticket = 7;
int old = std::exchange(ticket, ticket + 1);
std::cout << old << " then " << ticket << "\n";
}
2 in cart
2 bought, 0 left
7 then 8
How it works
std::exchange(items_, {})moves the current vector out as the return value and assigns an empty vector ({}) in its place. No strings are copied, and the object is left in a known, empty state, not a "valid but unspecified" one.- It works for any type: the
ticketexample is a handy "use the current number and advance it". addcombines everything from this module: a sink parameter, an early return for invalid input, and a move into the container.
Putting it together for your Log
Your Log is the same shape as Cart: a sink add that skips empty lines, a size, and a flush that hands over all the lines and leaves the log empty.
Your turn: write class Log:
void add(std::string line): a sink; ignore empty linesint size() conststd::vector<std::string> flush(): hand over all lines (no copies) and leave the log empty