C/C++ Arena

Step 2 of 6

Review: dangling references

std::string_view and references are cheap views of data owned by someone else. The classic review catch is a view that outlives what it points at. It compiles cleanly, often seems to work in testing (the freed memory still holds the old bytes for a while), and then prints garbage in production.

Red flags to look for:

Who owns the characters?

For every view, find the std::string (or literal) that owns its characters, and check that the owner lives at least as long as the view.

#include <iostream>
#include <string>
#include <string_view>
#include <utility>

std::string_view first_word(std::string_view s) {      // fine: points into the caller's text
    return s.substr(0, s.find(' '));
}

struct Label {
    std::string text;                                   // owns its characters
    explicit Label(std::string t) : text(std::move(t)) {}
};

Label make_label(int n) {
    return Label("item " + std::to_string(n));          // the temporary is moved into the member
}

int main() {
    std::string line = "hello big world";
    std::cout << first_word(line) << "\n";              // line outlives the view: safe

    Label l = make_label(7);
    std::cout << l.text << "\n";
}
hello
item 7

The rule of thumb: views for parameters, owning strings for members and for return values built inside the function.

Your task

This pull request adds a greeting helper and a Tag type. Both have lifetime bugs. Fix them by making each owner hold its own std::string. (The checks inspect the types too, since dangling-view bugs can seem to work by luck.)

Challenge 2

This pull request has two lifetime bugs. longest returns a reference that can outlive what it refers to, and make_counter returns a lambda that captures a local variable by reference. Fix them: longest should return a std::string by value, and the counter should keep its own count (capture by value and mark the lambda mutable).

Challenge 3

This pull request hands out pointers to players stored in a std::vector. When the vector grows, it moves its elements to new memory and every pointer handed out before dangles. Fix Registry so a Player* returned by add stays valid while more players are added: store them in a container whose elements never move, such as std::deque (when you only add at the ends).

Previous: Review: pagination Next: Review: leaks on the error path