☔
As we all know, a reference creates an alias for another thing. For example:
int a = 42; int &r = a; cout << "r=" << r << " a=" << a << '\n'; a = 99; cout << "r=" << r << " a=" << a << '\n'; r = 56; cout << "r=" << r << " a=" << a << '\n';
r=42 a=42 r=99 a=99 r=56 a=56
Let’s say that we want to change all the fives in this vector to negative fives:
vector<int> values = {3,1,4,1,5,9,2,6,5,3,5}; for (size_t i=0; i<values.size(); i++) if (values[i] == 5) values[i] = -5; for (size_t i=0; i<values.size(); i++) cout << values[i] << ' ';
3 1 4 1 -5 9 2 6 -5 3 -5
That works, but it’s a lot of repetition—quite a few instances of
values[i]
.
Let’s use a more modern loop to write out the numbers:
vector<int> values = {3,1,4,1,5,9,2,6,5,3,5}; for (size_t i=0; i<values.size(); i++) if (values[i] == 5) values[i] = -5; for (int v : values) cout << v << ' ';
3 1 4 1 -5 9 2 6 -5 3 -5
Hooray! One fewer values[i]
!
Let’s use that same technique to change 5 to −5:
vector<int> values = {3,1,4,1,5,9,2,6,5,3,5}; for (int v : values) if (v == 5) v = -5; for (int v : values) cout << v << ' ';
3 1 4 1 5 9 2 6 5 3 5
That didn’t work. Why?
REFERENCES!
vector<int> values = {3,1,4,1,5,9,2,6,5,3,5}; for (int &v : values) if (v == 5) v = -5; for (int v : values) cout << v << ' ';
3 1 4 1 -5 9 2 6 -5 3 -5
I need &v
in the first loop, because I’m changing the number.
I’m not changing anything in the second loop, so a reference
isn’t required.
Consider this file:
% cat ~cs253/pub/ducks Huey (red) Dewey (blue) Louie (green)
I want code that reads that file into a vector<string>
,
and converts the vowels to asterisks, so it looks like
censorship.
ifstream in("/s/bach/a/class/cs253/pub/ducks"); vector<string> ducks; string line; while (getline(in, line)) ducks.push_back(line); for (size_t i=0; i<ducks.size(); i++) for (size_t j=0; j<ducks[i].size(); j++) if (ducks[i][j]=='a' || ducks[i][j]=='e' || ducks[i][j]=='i' || ducks[i][j]=='o' || ducks[i][j]=='u') ducks[i][j] = '*'; for (size_t i=0; i<ducks.size(); i++) cout << ducks[i] << '\n';
H**y (r*d) D*w*y (bl**) L**** (gr**n)
That was horrible. So soon, we’ve forgotten all that we’ve learned.
ifstream in("/s/bach/a/class/cs253/pub/ducks"); vector<string> ducks; string line; while (getline(in, line)) ducks.push_back(line); for (string &s : ducks) for (size_t j=0; j<s.size(); j++) if (s[j]=='a' || s[j]=='e' || s[j]=='i' || s[j]=='o' || s[j]=='u') s[j] = '*'; for (string s : ducks) cout << s << '\n';
H**y (r*d) D*w*y (bl**) L**** (gr**n)
Better, but still awful.
ifstream in("/s/bach/a/class/cs253/pub/ducks"); vector<string> ducks; string line; while (getline(in, line)) ducks.push_back(line); for (string &s : ducks) for (char &c : s) if (c=='a' || c=='e' || c=='i' || c=='o' || c=='u') c = '*'; for (string s : ducks) cout << s << '\n';
H**y (r*d) D*w*y (bl**) L**** (gr**n)
Finally, it’s DRY! Still, we’re copying strings in the last loop.
ifstream in("/s/bach/a/class/cs253/pub/ducks"); vector<string> ducks; string line; while (getline(in, line)) ducks.push_back(line); for (string &s : ducks) for (char &c : s) if (c=='a' || c=='e' || c=='i' || c=='o' || c=='u') c = '*'; for (const string &s : ducks) cout << s << '\n';
H**y (r*d) D*w*y (bl**) L**** (gr**n)
DRY and efficient.
ifstream in("/s/bach/a/class/cs253/pub/ducks"); vector<string> ducks; string line; while (getline(in, line)) ducks.push_back(line); for (string &s : ducks) for (size_t p=0; (p = s.find_first_of("aeiou",p)) != s.npos; p++) s[p] = '*'; for (const string &s : ducks) cout << s << '\n';
H**y (r*d) D*w*y (bl**) L**** (gr**n)
A different approach.