Author: Hayden Smith
What's the best way to sum a vector of numbers?
C-style?
#include <iostream>
#include <vector>
int main() {
std::vector<int> nums{1,2,3,4,5};
int sum = 0;
for (int i = 0; i <= nums.size(); ++i) {
sum += i;
}
std::cout << sum << "\n";
};
#include <iostream>
#include <vector>
int main() {
std::vector<int> nums{1,2,3,4,5};
auto sum = 0;
for (auto it = nums.begin(); it != nums.end(); ++it) {
sum += *it;
}
std::cout << sum << "\n";
}
What's the best way to sum a vector of numbers?
Via an iterator? Or for-range?
#include <iostream>
#include <vector>
int main() {
std::vector<int> nums{1,2,3,4,5};
int sum = 0;
// Internally, this uses begin and end,
// but it abstracts it away.
for (const auto& i : nums) {
sum += i;
}
std::cout << sum << "\n";
}
demo207-simple-sum.cpp
demo208-simple-sum.cpp
(This is the underlying mechanics)
#include <iostream>
#include <numeric>
#include <vector>
int main() {
std::vector<int> nums{1,2,3,4,5};
int sum = std::accumulate(nums.begin(), nums.end(), 0);
std::cout << sum << "\n";
}
What's the best way to sum a vector of numbers?
Via use of an STL Algorithm
// What type of iterator is required here?
template <typename T, typename Container>
T sum(iterator_t<Container> first, iterator_t<Container> last) {
T total;
for (; first != last; ++first) {
total += *first;
}
return total
}
demo209-accum.cpp
#include <iostream>
#include <numeric>
#include <vector>
int main() {
std::vector<int> v{1,2,3,4,5};
int sum = std::accumulate(v.begin(), v.end(), 0);
// What is the type of std::multiplies<int>()
int product = std::accumulate(v.begin(), v.end(), 1, std::multiplies<int>());
auto midpoint = v.begin() + (v.size() / 2);
// This looks a lot harder to read. Why might it be better?
auto midpoint11 = std::next(v.begin(), std::distance(v.begin(), v.end()) / 2);
int sum2 = std::accumulate(v.begin(), midpoint, 0);
std::cout << sum << "\n";
}
We can also use algorithms to:
demo211-algos.cpp
#include <iostream>
#include <vector>
int main() {
std::vector<int> nums{1,2,3,4,5};
auto it = std::find(nums.begin(), nums.end(), 4);
if (it != nums.end()) {
std::cout << "Found it!" << "\n";
}
}
We can also use algorithms to:
demo212-find.cpp
#include <algorithm>
#include <iostream>
#include <list>
#include <vector>
int main() {
// Lower bound does a binary search, and returns the first value >= the argument.
std::vector<int> sortedVec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::lower_bound(sortedVec.begin(), sortedVec.end(), 5);
std::list<int> sortedLinkedList{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::lower_bound(sortedLinkedList.begin(), sortedLinkedList.end(), 5);
}
demo213-bound.cpp
#include <iostream>
#include <vector>
char to_upper(unsigned char value) {
return static_cast<char>(std::toupper(static_cast<unsigned char>(value)));
}
int main() {
std::string s = "hello world";
// Algorithms like transform, which have output iterators,
// use the other iterator as an output.
auto upper = std::string(s.size(), '\0');
std::transform(s.begin(), s.end(), upper.begin(), to_upper);
}
demo214-transform.cpp
Gives you an output iterator for a container that adds to the end of it
#include <iostream>
#include <vector>
char to_upper(char value) {
return static_cast<char>(std::toupper(static_cast<unsigned char>(value)));
}
int main() {
std::string s = "hello world";
// std::for_each modifies each element
std::for_each(s.begin(), s.end(), toupper);
std::string upper;
// std::transform adds to third iterator.
std::transform(s.begin(), s.end(), std::back_inserter(upper), to_upper);
}
demo215-inserter.cpp
#include <iostream>
#include <vector>
int main() {
std::string s = "hello world";
// std::for_each modifies each element
std::for_each(s.begin(), s.end(), [] (char& value) { value = std::toupper(value); });
}
demo216-lambda1.cpp
[](card const c) -> bool {
return c.colour == 4;
}
[capture] (parameters) -> return {
body
}
#include <iostream>
#include <vector>
void add_n(std::vector<int>& v, int n) {
std::for_each(v.begin(), v.end(), [n] (int& val) { val = val + n; });
}
int main() {
std::vector<int> v{1,2,3};
add_n(v, 3);
}
demo217-lambda2.cpp
Operation | Output | Input | Forward | Bidirectional | Random Access |
---|---|---|---|---|---|
Read | =*p | =*p | =*p | =*p | |
Access | -> | -> | -> | -> [] | |
Write | *p= | *p= | *p= | *p= | |
Iteration | ++ | ++ | ++ | ++ -- | ++ -- + - += -= |
Compare | == != | == != | == != | == != < > <= >= |
More powerful
Forward
Bidir.
Random
"->" no longer specified as of C++20
Input
Output
An algorithm requires certain kinds of iterators for their operations
A container's iterator falls into a certain category
stack, queue are container adapters, and do not have iterators