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:
- returning a
string_viewor a reference to a local or a temporary - storing a
string_viewmember initialized from a temporarystd::string - keeping a reference into a container that later grows
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
first_wordis safe because it returns a view into the caller's string, which is still alive when the view is used.Labelstores astd::string, not a view. The temporary"item " + ...would die at the end of the statement, so astring_viewmember would dangle; an owning member takes the characters with it.
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