marp | math | theme | paginate | footer |
---|---|---|---|---|
true |
katex |
custom-theme |
true |
STL stands for Standard Template Library We're gonna talk about it a lot!
std::pair
std::array
std::vector
std::string
- Aggregate initialization
📺 Watch the related YouTube video!
- This lecture is beginner friendly
- There are some best practices that would use different types, but those require more in-depth understanding and will be covered later
- What you see on this slide is the best practice until this point in the course 😉
- 🎨 - Style recommendation
- 🎓 - Software design recommendation
- 😱 - Not a good practice! Avoid in real life!
- ✅ - Good practice!
- ❌ - Whatever is marked with this is wrong
- 🚨 - Alert! Important information!
- 💡 - Hint or a useful exercise
- 🔼1️⃣7️⃣ - Holds for this version of C++(here, 17) and above
- 🔽1️⃣1️⃣ - Holds for versions until this one C++(here, 11)
Style (🎨) and software design (🎓) recommendations mostly come from Google Style Sheet and the CppCoreGuidelines
#include <utility>
to usestd::pair
- Allows storing values of two types
std::pair<T1, T2>
std::pair<int, std::string> pair{42, "The answer"};
- 🔼1️⃣7️⃣ The types will be guessed by the compiler:
std::pair pair{42, "The answer"};
- Access the data with
.first
and.second
#include <iostream>
#include <utility>
int main() {
std::pair pair{"The answer", 42};
std::cout << pair.first << " is " << pair.second << std::endl;
return 0;
}
- 🔼1️⃣1️⃣
#include <array>
to usestd::array
- 🚨 The size must be known at compile time
- Create from data:
🔼1️⃣7️⃣
std::array arr = {1, 2, 3};
🔼1️⃣7️⃣std::array arr{1, 2, 3};
🔼1️⃣4️⃣std::array<int, 3UL> arr{1, 2, 3};
🔼1️⃣1️⃣std::array<int, 3UL> arr = {1, 2, 3};
1️⃣1️⃣std::array<int, 3UL> arr{{1, 2, 3}};
- In the newer standards, compiler guesses type and size
- 🚨 Beware of double brackets in
C++11
!
- Check if container is empty with
arr.empty()
- Get number of stored values with
arr.size()
- Indexing from
0UL
up toarr.size() - 1UL
- Get element by index without bound check with
[index]
🚨 Make sure the element exists! UB otherwise! - Get element by index with bound check with
.at(index)
- Useful access aliases:
- First item:
arr.front()
$\Leftrightarrow$ arr[0UL]
- Last item:
arr.back()
$\Leftrightarrow$ arr[arr.size() - 1UL]
#include <array> #include <iostream> int main() { const std::array arr{1, 2, 3}; std::cout << arr[0] << " " << arr.back() << std::endl; return 0; }
- First item:
#include <vector>
to usestd::vector
- Vector is implemented as a dynamic table
- Create similarly to the
std::array
:- 🔼1️⃣7️⃣
std::vector vec{1, 2, 3};
- 🔼1️⃣7️⃣
std::vector vec = {1, 2, 3};
- 🔼1️⃣1️⃣
std::vector<int> vec{1, 2, 3};
- 🔼1️⃣1️⃣
std::vector<int> vec = {1, 2, 3};
- 🔼1️⃣7️⃣
- Access stored elements just like in
std::array
But we can also change the accessed values! - ✅ Use
std::vector
a lot! It is fast and flexible! - 💡 Think of it as a default container to store items
- 🚨 Cannot be
constexpr
(🔽2️⃣0️⃣)
- Remove all elements:
vec.clear()
- Add a new item in one of two ways:
- 🔼1️⃣1️⃣
vec.emplace_back(value)
vec.push_back(value)
- historically better known
- 🔼1️⃣1️⃣
- Resize vector with
vec.resize(new_size)
- If
new_size
is smaller thanvec.size()
the elements at the end of the vector will be destroyed - Otherwise, new uninitialized elements will be added
Use
vec.resize(new_size, value)
to initialize them
- If
- Remove last element with
vec.pop_back()
🚨 Make sure vector is not empty! UB otherwise! - There are other ways to insert/remove elements, stay tuned
- Adding elements to
std::vector
changes its size - Changing size might allocate memory, which is slow
- If we expect to add elements often, we can optimize!
reserve(n)
allocates enough memory to storen
items but does not change thesize()
of the vector- This is a very important optimization
- Do it if you know (even just approximately) the number of elements you plan to add in advance
// Somewhere in some function std::vector<std::string> vec; const int number_of_iterations = 100; // Always call reserve when you know the size. vec.reserve(number_of_iterations); for (int i = 0; i < number_of_iterations; ++i) { vec.emplace_back("hello"); }
#include <iostream>
#include <string>
#include <vector>
using std::cout;
using std::endl;
using std::string;
using std::vector;
int main() {
const vector numbers = {1, 2, 3};
vector<std::string> jedi = {"Yoda", "Anakin"};
jedi.reserve(jedi.size() + 1UL); // 💡optional
jedi.push_back("Obi-Wan");
cout << "Some Jedi: " << jedi.front() << endl;
cout << "Last number: " << numbers.back() << endl;
return 0;
}
#include <string>
to usestd::string
- Access contents just like in vectors or arrays
- Concatenate strings with
+
using std::string_literals::operator""s;
allows to use ans
string literal suffix (likef
forfloat
)
#include <iostream>
#include <string>
int main() {
using std::string_literals::operator""s;
const std::string hello = "Hello"s;
std::cout << "Type your name:" << std::endl;
std::string name{}; // Init empty
std::cin >> name; // Read name
std::cout << hello + ", "s + name + "!"s << std::endl;
std::cout << "Name length is: " << name.size() << std::endl;
return 0;
}
- 🚨 Not available at compile time, cannot be
constexpr
- Use
std::to_string
to convert variables of fundamental types tostd::string
- Use
std::sto[i|d|f|ul]
etc. to convert from strings:-
std::stoi
:std::string
$\rightarrow$ int
-
std::stof
:std::string
$\rightarrow$ float
-
std::stod
:std::string
$\rightarrow$ double
-
std::stoul
:std::string
$\rightarrow$ unsigned long
- There are more flavors (click the links 😉)
-
// Somewhere in some function
const int starting_number{42};
const std::string some_string{std::to_string(starting_number)};
int recovered_number{std::stoi(some_string)};
// It will even ignore the text after the number!
int another_number{std::stoi("42 is the number")};
// Try it with other types and negative numbers too!
- Technically
std::string
is not a sequence container - Be careful when creating containers with strings:
Reason: compiler will use C-style
char
arrays instead ofstd::string
as a storage type - 💡
std::vector
has a special 2-element constructor:const std::size_t size{10}; const int content{42}; // Creates a vector of 10 elements and fills it with value 42 // 🚨 Note the round brackets! 🚨 const std::vector vec_full_of_42(size, content); // 🚨 Using curly brackets creates vector with elements {10, 42} const std::vector vec_10_and_42{size, content};
- ❌
std::vector<bool>
is weird! Reason: it does not behave like avector
, which is confusing Use only if you know that you're doing (probably don't)
- Used to initialize multiple variables at the same time
- 🚨 We must use
auto
- Also supports
const
and references (&
) - Example with
std::array
:const std::array arr{1, 2, 3}; // Initialize a = 1, b = 2, c = 3 const auto [a, b, c] = arr;
- Example with
std::pair
:using std::string_literals::operator""s; const std::pair pair{"Hello"s, "World"s}; // Initialize hello = "Hello", world = "World" const auto& [hello, world] = pair; // Note the &
- There are more containers:
std::deque
(we might cover later)std::list
- 🔼1️⃣1️⃣
std::forward_list
- The can be useful but are a lot less often used
- I don't remember the last time I used
std::list
🤷 - I'll leave lists for you to figure out on your own (later)