#include <iostream>
#include <vector>
#include <string>
struct T {
T() = default;
T(int i, double d, const std::string& s) : i_(i), d_(d), s_(s) {}
int i_;
double d_;
std::string s_;
friend std::ostream& operator << (std::ostream& to, const T& t) {
return to << '[' << t.i_ << ',' << t.d_ << ',' << t.s_ << ']';
}
};
using TVec = std::vector<T>;
void status(const char* label, const TVec& tv)
{
std::cout << label << ":\n";
std::cout << "tv.empty() == " << (tv.empty() ? "true" : "false") << "\n";
if (tv.empty() == false) {
std::cout << "+ tv.front() == " << tv.front() << "\n";
std::cout << "+ tv.back() == " << tv.back() << "\n";
}
std::cout << "tv.capacity() == " << tv.capacity() << "\n";
std::cout << "tv.size() == " << tv.size() << "\n";
std::cout << "\n";
}
int main() {
TVec tv;
status("start", tv);
tv.reserve(10); // pre-allocate room for 10.
status("after reserve", tv);
tv.emplace_back(0, 42., "first");
status("after first", tv);
{
T temp { 1, 42., "second" };
tv.push_back(temp); // copy temp to new entry in tv.
}
status("after second", tv);
tv.emplace_back(2, 50., "third");
status("after third", tv);
std::cout << "tv[1].s_ = " << tv[1].s_ << "\n";
// C++'s standard library heavily uses something called "iterators",
// these are variables that reference entries in a container like a
// vector. An iterator lets you ask a question like "find me an element
// with this value" or "tell me the start and end of a range".
// The most natural range is the start and end of the container.
// These are `begin` and `end`. `begin` references the first element
// while `end` references *beyond* the last element. This is an
// important distinction because it lets you determine if something is
// *not* in a container.
std::cout << "Contents of tv using iterators:\n";
for (auto it = tv.begin(); it != tv.end(); ++it) {
// "it" is the iterator itself, like a pointer,
// "*it" is the entry the iterator references.
std::cout << " " << *it << "\n";
}
// there's also insertion: here we'll insert infront of the first entry
tv.insert(tv.begin(), T { -1, -1., "sneaky" });
status("after sneaky", tv);
std::cout << "Contents of tv using range-based for:\n";
for (auto&& t : tv) {
// 'auto t' would *copy* every T in tv into `t`, which is wasteful,
// 'auto&& t' will use a reference if it can, which saves cpu
std::cout << " " << t << "\n"; // note no need to do '*'.
}
// now lets remove the element *after* sneaky
tv.erase(tv.begin() + 1);
status("after erase", tv);
// finally, one last magical function
tv.clear();
status("after clear", tv);
}