AdvC++ - pierwszy commit

This commit is contained in:
Sasza Stanczew 2024-04-25 09:39:28 +02:00
parent 1e9b877c94
commit 477331dd9a
236 changed files with 35528 additions and 0 deletions

32
AdvancedCppV2/.gitignore vendored Normal file
View file

@ -0,0 +1,32 @@
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app

19
AdvancedCppV2/LICENSE Normal file
View file

@ -0,0 +1,19 @@
Copyright (C) 2020 Hakim El Hattab, http://hakim.se, and reveal.js contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -0,0 +1,26 @@
<!-- .slide: data-background="#ccc" -->
### Agenda
* <!-- .element: class="fragment fade-in" --> Cloning and building example project
* <!-- .element: class="fragment fade-in" --> What's new since C++98
* <!-- .element: class="fragment fade-in" --> C++11
* <!-- .element: class="fragment fade-in" --> C++14
* <!-- .element: class="fragment fade-in" --> C++17
* <!-- .element: class="fragment fade-in" --> C++20
* <!-- .element: class="fragment fade-in" --> Smart pointers
- <!-- .element: class="fragment fade-in" --> <code>std::unique_ptr<></code>
- <!-- .element: class="fragment fade-in" --> <code>std::shared_ptr<></code>
- <!-- .element: class="fragment fade-in" --> <code>std::weak_ptr<></code>
- <!-- .element: class="fragment fade-in" --> Best practices
- <!-- .element: class="fragment fade-in" --> Implementation details
- <!-- .element: class="fragment fade-in" --> Efficiency
* <!-- .element: class="fragment fade-in" --> Templates
* <!-- .element: class="fragment fade-in" --> Basics
* <!-- .element: class="fragment fade-in" --> Typetraits
* <!-- .element: class="fragment fade-in" --> Specializations
* <!-- .element: class="fragment fade-in" --> Partial specializations
* <!-- .element: class="fragment fade-in" --> Templates variable
* <!-- .element: class="fragment fade-in" --> Deduction guides
<!-- .slide: style="font-size: 0.90em" -->

View file

@ -0,0 +1,46 @@
# Cloning and building example project
<!-- .slide: data-background="#ccc" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Setup
* <!-- .element: class="fragment fade-in" --> Clone repository: https://github.com/nauka-programowania-MA/AdvancedCppV2
* <!-- .element: class="fragment fade-in" --> Go to exercises/exampleProject
* <!-- .element: class="fragment fade-in" --> Compile it and run:
* <!-- .element: class="fragment fade-in" --> <code>mkdir build</code>
* <!-- .element: class="fragment fade-in" --> <code>cd build</code>
* <!-- .element: class="fragment fade-in" --> cmake ..
* <!-- .element: class="fragment fade-in" --> make -j4 (where 4 is available threads)
* <!-- .element: class="fragment fade-in" --> ./ExampleProject
* <!-- .element: class="fragment fade-in" --> Should print <code>Hello World</code>
If you don't have linux, you can use <a href="https://replit.com/">replit</a>
<!-- .element: class="fragment fade-in" -->
* <!-- .element: class="fragment fade-in" --> Click Create C++
* <!-- .element: class="fragment fade-in" --> Name it and confirm with button Create Repl.
* <!-- .element: class="fragment fade-in" --> Click three dot on the rigt top screen and click upload folder
* <!-- .element: class="fragment fade-in" --> Now find your directory with repo and upload it
* <!-- .element: class="fragment fade-in" --> Congratulation, you can use linux shell wit sanitizers, cmake and valgridn support :)
<!-- .element: class="fragment fade-in" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## replit
If you decided to use replit please configure this file: `replit.nix`:
```bash
{ pkgs }: {
deps = [
pkgs.clang_12
pkgs.ccls
pkgs.gdb
pkgs.gnumake
pkgs.vim
pkgs.valgrind
pkgs.cmake
];
}
```

View file

@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.2)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
project(Complex)
set(SRC_LIST
complex.cpp
)
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_compile_options(${PROJECT_NAME} PUBLIC -Wall -Werror -Wpedantic -Wextra)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR})

View file

@ -0,0 +1,16 @@
## Linux compilation
> mkdir build
> cd build
> cmake -DCMAKE_BUILD_TYPE=Debug ..
> make
## Exercise 1
Write a function that creates `std::complex` number from two provided numbers. If the types of numbers are different, it should create `std::complex` of the first parameter. Usage:
```c++
std::complex<int> a = makeComplex(4, 5); // both ints
std::complex<double> b = makeComplex(3.0, 2.0); // both doubles
std::complex<int> c = makeComplex(1, 5.0); // int, double -> takes int
```

View file

@ -0,0 +1 @@
#include <complex>

View file

@ -0,0 +1,6 @@
#include <complex>
template <typename T, typename U>
std::complex<T> makeComplex(T a, U b) {
return std::complex<T>{a, static_cast<T>(b)};
}

View file

@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.2)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
project(Converter)
set(SRC_LIST
converter.cpp
)
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_compile_options(${PROJECT_NAME} PUBLIC -Wall -Werror -Wpedantic -Wextra)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR})

View file

@ -0,0 +1,18 @@
## Linux compilation
> mkdir build
> cd build
> cmake -DCMAKE_BUILD_TYPE=Debug ..
> make
## Valgrind usage
> valgrind valgrind_params path/to/binary binary_params, eg:
> valgrind --leak-check=full ./Converter
> or full output using command: valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose --log-file=valgrind-out.txt ./Converter
## Converter exapmle
1. Compile and run Converter application and check memory leaks under valgrind
2. Fix code using std::unique_ptr and std::make_unique
3. Find other issues and fix them (use good practise etc...)

View file

@ -0,0 +1,59 @@
#include <iostream>
#include <memory>
#include <stdexcept>
class Resource {
public:
Resource(const std::string& str): str_(str) {}
const std::string& str() const {
return str_;
}
private:
std::string str_;
};
class Converter {
public:
virtual void Convert(Resource* resource) = 0;
};
class CurlyBracketConverter : public Converter {
public:
virtual void Convert(Resource* resource) {
std::cout << "{" << resource->str() << "}\n";
}
};
class SquareBracketConverter : public Converter {
public:
virtual void Convert(Resource* resource) {
std::cout << "[" << resource->str() << "]\n";
}
};
class Printer {
public:
Printer(Converter* converter): converter_(converter) {}
void Print(Resource* resource) {
converter_->Convert(resource);
}
private:
Converter* converter_;
};
int main() {
Resource* resource = new Resource("Ala has a cat");
Printer printer(new SquareBracketConverter{});
Printer printer2(new CurlyBracketConverter{});
printer.Print(resource);
printer2.Print(resource);
delete resource;
return 0;
}

View file

@ -0,0 +1,84 @@
#include <iostream>
#include <memory>
#include <stdexcept>
class Resource {
public:
explicit Resource(const std::string& str): str_(str) {}
const std::string& str() const {
return str_;
}
private:
std::string str_;
};
class Converter {
public:
Converter() = default;
// Rule of 5
virtual ~Converter() = default;
Converter(const Converter& other) = default;
Converter(Converter&& other) = default;
Converter& operator=(const Converter& other) = default;
Converter& operator=(Converter&& other) = default;
virtual void Convert(const std::unique_ptr<Resource>& resource) const = 0;
};
class CurlyBracketConverter : public Converter {
public:
void Convert(const std::unique_ptr<Resource>& resource) const override {
std::cout << "{" << resource->str() << "}\n";
}
};
class SquareBracketConverter : public Converter {
public:
virtual void Convert(const std::unique_ptr<Resource>& resource) const override{
std::cout << "[" << resource->str() << "]\n";
}
};
class Printer {
public:
explicit Printer(std::unique_ptr<Converter>&& converter) noexcept : converter_(std::move(converter)) {}
void Print(const std::unique_ptr<Resource>& resource) const {
converter_->Convert(resource);
}
private:
std::unique_ptr<Converter> converter_;
};
struct Foo {
Foo(std::unique_ptr<int> ptr);
};
struct Bar {
use(std::unique_ptr<Foo> ptr);
};
struct MockFoo {};
TEST() {
std::unique_ptr<MockFoo> mock;
MockFoo* mock_ptr = mock.get();
Bar bar;
bar.use(std::move(mock));
EXPECT_CALL(mock_ptr, use);
}
int main() {
auto resource = std::make_unique<Resource>("Ala has a cat");
Printer printer(std::make_unique<SquareBracketConverter>());
Printer printer2(std::make_unique<CurlyBracketConverter>());
printer.Print(resource);
printer2.Print(resource);
return 0;
}

View file

@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.2)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
project(ExampleProject)
set(SRC_LIST
exampleProject.cpp
)
add_executable(${PROJECT_NAME} ${SRC_LIST})
# target_compile_options(${PROJECT_NAME} PUBLIC -Wall -Werror -Wpedantic -Wextra)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR})

View file

@ -0,0 +1,10 @@
## Linux compilation
> mkdir build
> cd build
> cmake -DCMAKE_BUILD_TYPE=Debug ..
> make
## Run program
Run program ./ExampleProject and check output, which should be "Hello World";

View file

@ -0,0 +1,7 @@
#include <string>
#include <iostream>
int main() {
const std::string str("Hello world!\n");
std::cout << str << '\n';
}

View file

@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.2)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
project(List)
set(SRC_LIST
list.cpp
)
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_compile_options(${PROJECT_NAME} PUBLIC -Wall -Werror -Wpedantic -Wextra)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR})

View file

@ -0,0 +1,25 @@
## Linux compilation
> mkdir build
> cd build
> cmake -DCMAKE_BUILD_TYPE=Debug ..
> make
## Valgrind usage
> valgrind valgrind_params path/to/binary binary_params, eg:
> valgrind --leak-check=full ./List
> or full output using command: valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose --log-file=valgrind-out.txt ./List
## Resource exapmle
Take a look at `list.cpp` file, where simple (and buggy) single-linked list is implemented.
* `pushFront` method adds a new `Node` at the begining of the list.
* `findByValue` method iterates over the list and returns the first Node with matching `value` or `nullptr`.
1. Compile and run List application
2. Fix memory leaks without introducing smart pointers
3. Fix memory leaks with smart pointers. What kind of pointers needs to be applied and why?
4. Add function to add a node at the end of the list (try to do this with time complexity O(1))
5. Add function to delete node with provided value.

View file

@ -0,0 +1,68 @@
#include <iostream>
class Node {
public:
Node(const int value, Node* next)
: next_(next), value_(value) {}
explicit Node(const int v)
: Node(v, nullptr) {}
const Node* next() const { return next_; }
int value() const { return value_; }
private:
Node* next_;
int value_;
};
class List {
public:
void pushFront(int value) {
if (!head_) {
head_ = new Node(value);
return;
}
head_ = new Node(value, head_);
}
const Node* findByValue(const int value) const {
const auto* current = head_;
while (current) {
if (current->value() == value) {
return current;
}
current = current->next();
}
return nullptr;
}
private:
Node* head_ = nullptr;
};
int main() {
List list;
list.pushFront(4);
list.pushFront(2);
list.pushFront(7);
list.pushFront(9);
if (const auto* const node = list.findByValue(1)) {
std::cout << node->value() << '\n';
} else {
std::cout << "can't find node with value 1\n";
}
if (const auto* const node = list.findByValue(7)) {
std::cout << node->value() << '\n';
} else {
std::cout << "can't find node with value 7\n";
}
return 0;
}

View file

@ -0,0 +1,76 @@
#include <iostream>
#include <memory>
#include <utility>
class Node {
public:
Node(const int value, std::unique_ptr<Node> next)
: next_(std::move(next)), value_(value) {}
explicit Node(const int v)
: Node(v, nullptr) {}
const Node* next() const { return next_.get(); }
int value() const { return value_; }
std::unique_ptr<Node> getNext() { return std::move(next_); }
private:
std::unique_ptr<Node> next_;
int value_;
};
// 1
// 2 -> 1
// 3 -> 2 -> 1
// 4 -> 3 -> 2 -> 1
class List {
public:
void pushFront(int value) {
if (!head_) {
head_ = std::make_unique<Node>(value);
return;
}
head_ = std::make_unique<Node>(value, std::move(head_));
}
const Node* findByValue(const int value) const {
const auto* current = head_.get();
while (current) {
if (current->value() == value) {
return current;
}
current = current->next();
}
return nullptr;
}
private:
std::unique_ptr<Node> head_;
};
int main() {
List list;
list.pushFront(4);
list.pushFront(2);
list.pushFront(7);
list.pushFront(9);
if (const auto* const node = list.findByValue(1)) {
std::cout << node->value() << '\n';
} else {
std::cout << "can't find node with value 1\n";
}
if (const auto* const node = list.findByValue(7)) {
std::cout << node->value() << '\n';
} else {
std::cout << "can't find node with value 7\n";
}
return 0;
}

View file

@ -0,0 +1,181 @@
#include <iostream>
#include <memory>
#include <utility>
class Node {
public:
Node(const int value, std::unique_ptr<Node> next)
: next_(std::move(next)), value_(value) {}
explicit Node(const int v)
: Node(v, nullptr) {}
const Node* next() const { return next_.get(); }
Node* next() { return next_.get(); }
int value() const { return value_; }
void setNext(std::unique_ptr<Node> next) { next_ = std::move(next); }
std::unique_ptr<Node> getNext() { return std::move(next_); }
private:
std::unique_ptr<Node> next_;
int value_;
};
// ht
// 1
// h t
// 2 -> 1
// h t
// 3 -> 2 -> 1
// h t
// 4 -> 3 -> 2 -> 1
// h t
// 4 -> 3 -> 2 -> 1 -> 5
//
// 3 -> 2 -> 1 -> 5
// 3 -> 1 -> 5
class List {
public:
void pushFront(int value) {
if (!head_) {
pushHead(value);
return;
}
head_ = std::make_unique<Node>(value, std::move(head_));
}
void pushBack(int value) {
if (!tail_) {
pushHead(value);
return;
}
tail_->setNext(std::make_unique<Node>(value));
tail_ = tail_->next();
}
bool erase(int value) {
// Remove head
if (head_ && head_->value() == value) {
head_ = head_->getNext();
if (!head_) {
tail_ = nullptr;
}
return true;
}
if (auto* node = findPrevNode(value)) {
// Remove tail
if (node->next() == tail_) {
tail_ = node;
}
node->setNext(std::move(node->next()->getNext()));
return true;
}
return false;
}
const Node* findByValue(const int value) const {
const auto* current = head_.get();
while (current) {
if (current->value() == value) {
return current;
}
current = current->next();
}
return nullptr;
}
void print() const {
const auto* current = head_.get();
while (current) {
std::cout << current->value() << ' ';
current = current->next();
}
std::cout << '\n';
}
private:
// ht
// 1
// h t
// 2 -> 1
// h t
// 2 -> 1 -> 3
// 2 -> 3
void pushHead(int value) {
head_ = std::make_unique<Node>(value);
tail_ = head_.get();
}
Node* findPrevNode(const int value) const {
auto* current = head_.get();
Node* prev = nullptr;
while (current) {
if (current->value() == value) {
return prev;
}
prev = current;
current = current->next();
}
return nullptr;
}
std::unique_ptr<Node> head_;
Node* tail_{nullptr};
};
int main() {
List list;
list.pushFront(4);
list.pushFront(2);
list.pushFront(7);
list.pushFront(9);
list.print();
if (const auto* const node = list.findByValue(1)) {
std::cout << node->value() << '\n';
} else {
std::cout << "can't find node with value 1\n";
}
if (const auto* const node = list.findByValue(7)) {
std::cout << node->value() << '\n';
} else {
std::cout << "can't find node with value 7\n";
}
list.pushBack(10);
list.print();
list.pushBack(12);
list.pushFront(3);
list.pushFront(5);
list.pushBack(13);
list.print();
list.erase(2);
list.print();
list.erase(5);
list.print();
list.erase(13);
list.print();
list.erase(12);
list.print();
list.pushBack(40);
list.print();
return 0;
}

View file

@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.2)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
project(Map)
set(SRC_LIST
map.cpp
)
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_compile_options(${PROJECT_NAME} PUBLIC -Wall -Werror -Wpedantic -Wextra)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR})

View file

@ -0,0 +1,55 @@
## Linux compilation
> mkdir build
> cd build
> cmake -DCMAKE_BUILD_TYPE=Debug ..
> make
## Exercise 1
Write a template class `VectorMap` that represents an over-engineered `std::map`.
Inside, it should hold 2 `std::vectors` of the same size, each with different types. The first vector should hold keys, the other one values.
Elements at the same position in both vectors should create a pair like `1` and `'c'` below.
```c++
VectorMap<int, char> map;
map.insert(1, 'c');
map[1] = 'e'; // replaces value under 1
std::cout << map[1]; // prints 'e'
map.at(2); // throw std::out_of_range
```
Implement the mentioned above `insert()`, `operator[]`, `at()` methods.
Do not bother about duplicated keys for now.
You can also try to implement additional methods from the `std::map` interface 🙂
Use [cppreference](http://en.cppreference.com/w/cpp/container/map).
## Exercise 2 - `static_assert`
Add a constraint to our `VectorMap`.
Do not allow to create an object when `ValueType` does not have a default constructor.
Use `static_assert` and proper trait from [`<type_traits>`](https://en.cppreference.com/w/cpp/types#Type_traits) library.
Check if it works properly.
## Exercise 3 - `isIntKey()`
Write a function `isIntKey()` in `VectorMap`. It should return `true` when the KeyType is `int` and `false` otherwise.
Check the [`<type_traits>`](https://en.cppreference.com/w/cpp/types#Type_traits) library for some inspiration 🙂
# Exercie 4
Write a partial specialization of `VectorMap` for boolean keys. We can have only 2 values for boolean keys. There is no need to keep vectors inside.
Implement properly all currently available functions.
# Exercie 5
Write a variable template `is_int_key_v`. It should return a value of the `is_int_key` field in a given template type.

View file

@ -0,0 +1,4 @@
#include <algorithm>
#include <iostream>
#include <type_traits>
#include <vector>

View file

@ -0,0 +1,44 @@
#include <algorithm>
#include <iostream>
#include <type_traits>
#include <vector>
template <typename Key, typename Value>
class VectorMap {
std::vector<Key> keys_;
std::vector<Value> values_;
public:
using K = Key;
using V = Value;
void insert(const Key& k, const Value& v) {
keys_.emplace_back(k);
values_.emplace_back(v);
}
Value& operator[](const Key& k);
Value& at(const Key& k);
};
template <typename Key, typename Value>
Value& VectorMap<Key, Value>::operator[](const Key& k) {
auto it = std::find(std::begin(keys_), std::end(keys_), k);
if (it == std::end(keys_)) {
keys_.emplace_back(k);
values_.emplace_back(Value{});
return values_.back();
}
auto dist = std::distance(keys_.begin(), it);
return values_[dist];
}
template <typename Key, typename Value>
Value& VectorMap<Key, Value>::at(const Key& k) {
auto it = std::find(std::begin(keys_), std::end(keys_), k);
if (it == std::end(keys_)) {
throw std::out_of_range("This key does not exist");
}
auto dist = std::distance(keys_.begin(), it);
return values_[dist];
}

View file

@ -0,0 +1,54 @@
#include <algorithm>
#include <iostream>
#include <type_traits>
#include <vector>
template <typename Key, typename Value>
class VectorMap {
std::vector<Key> keys_;
std::vector<Value> values_;
static_assert(std::is_default_constructible<Value>::value, "Value should have the default constructor");
static_assert(std::is_default_constructible_v<Value>, "Value should have the default constructor");
public:
using K = Key;
using V = Value;
void insert(const Key& k, const Value& v) {
keys_.emplace_back(k);
values_.emplace_back(v);
}
static constexpr bool isIntKey() {
// if (std::is_integral_v<Key>) {
if (std::is_same_v<Key, int>) {
return true;
}
return false;
}
Value& operator[](const Key& k);
Value& at(const Key& k);
};
template <typename Key, typename Value>
Value& VectorMap<Key, Value>::operator[](const Key& k) {
auto it = std::find(std::begin(keys_), std::end(keys_), k);
if (it == std::end(keys_)) {
keys_.emplace_back(k);
values_.emplace_back(Value{});
return values_.back();
}
auto dist = std::distance(keys_.begin(), it);
return values_[dist];
}
template <typename Key, typename Value>
Value& VectorMap<Key, Value>::at(const Key& k) {
auto it = std::find(std::begin(keys_), std::end(keys_), k);
if (it == std::end(keys_)) {
throw std::out_of_range("This key does not exist");
}
auto dist = std::distance(keys_.begin(), it);
return values_[dist];
}

View file

@ -0,0 +1,56 @@
#include <algorithm>
#include <iostream>
#include <type_traits>
#include <vector>
template <typename Key, typename Value>
class VectorMap {
std::vector<Key> keys_;
std::vector<Value> values_;
static_assert(std::is_default_constructible<Value>::value, "Value should have the default constructor");
static_assert(std::is_default_constructible_v<Value>, "Value should have the default constructor");
public:
using K = Key;
using V = Value;
void insert(const Key& k, const Value& v) {
keys_.emplace_back(k);
values_.emplace_back(v);
}
static constexpr bool isIntKey() {
// if (std::is_integral_v<Key>) {
if (std::is_same_v<Key, int>) {
return true;
}
return false;
}
Value& operator[](const Key& k);
Value& at(const Key& k);
static constexpr bool is_int_key = std::is_same_v<Key, int>;
};
template <typename Key, typename Value>
Value& VectorMap<Key, Value>::operator[](const Key& k) {
auto it = std::find(std::begin(keys_), std::end(keys_), k);
if (it == std::end(keys_)) {
keys_.emplace_back(k);
values_.emplace_back(Value{});
return values_.back();
}
auto dist = std::distance(keys_.begin(), it);
return values_[dist];
}
template <typename Key, typename Value>
Value& VectorMap<Key, Value>::at(const Key& k) {
auto it = std::find(std::begin(keys_), std::end(keys_), k);
if (it == std::end(keys_)) {
throw std::out_of_range("This key does not exist");
}
auto dist = std::distance(keys_.begin(), it);
return values_[dist];
}

View file

@ -0,0 +1,125 @@
#include <algorithm>
#include <iostream>
#include <type_traits>
#include <vector>
template <typename Key, typename Value>
class VectorMap {
std::vector<Key> keys_;
std::vector<Value> values_;
static_assert(std::is_default_constructible<Value>::value, "Value should have the default constructor");
static_assert(std::is_default_constructible_v<Value>, "Value should have the default constructor");
public:
using K = Key;
using V = Value;
template <typename T>
using iterator = typename std::vector<T>::iterator;
void insert(const Key& k, const Value& v) {
keys_.emplace_back(k);
values_.emplace_back(v);
}
static constexpr bool isIntKey() {
// if (std::is_integral_v<Key>) {
if (std::is_same_v<Key, int>) {
return true;
}
return false;
}
Value& operator[](const Key& k);
Value& at(const Key& k);
static constexpr bool is_int_key = std::is_same_v<Key, int>;
};
template <typename Key, typename Value>
Value& VectorMap<Key, Value>::operator[](const Key& k) {
auto it = std::find(std::begin(keys_), std::end(keys_), k);
if (it == std::end(keys_)) {
keys_.emplace_back(k);
values_.emplace_back(Value{});
return values_.back();
}
auto dist = std::distance(keys_.begin(), it);
return values_[dist];
}
template <typename Key, typename Value>
Value& VectorMap<Key, Value>::at(const Key& k) {
auto it = std::find(std::begin(keys_), std::end(keys_), k);
if (it == std::end(keys_)) {
throw std::out_of_range("This key does not exist");
}
auto dist = std::distance(keys_.begin(), it);
return values_[dist];
}
template <typename ValueType>
class VectorMap<bool, ValueType> { // specialization
static_assert(std::is_default_constructible<ValueType>::value,
"ValueType must have the default constructor");
ValueType t_;
ValueType f_;
public:
static constexpr bool is_int_key = false; // type_traits #2
VectorMap() {
std::cout << "bool specialization used\n";
}
void insert(bool key, ValueType&& value) {
if (key) {
t_ = value;
} else {
f_ = value;
}
}
ValueType& operator[](bool key) {
if (key) {
return t_;
}
return f_;
}
ValueType& at(bool key) {
if (key) {
return t_;
}
return f_;
}
};
int main() {
VectorMap<int, char> map;
// VectorMap<int, char>::iterator<K> k;
map.insert(1, 'c');
std::cout << map[1] << '\n';
map[1] = 'e'; // replaces value under 1
std::cout << map[1] << '\n'; // prints 'e'
// map.at(2); // throw std::out_of_range
std::cout << std::boolalpha << map.isIntKey() << '\n';
std::cout << std::boolalpha << map.is_int_key << '\n';
VectorMap<char, char> map3;
std::cout << std::boolalpha << map3.isIntKey() << '\n';
VectorMap<bool, int> map4;
map4.insert(true, 3);
map4.insert(false, 0);
std::cout << map4[true] << '\n';
map4[true] = 10; // replaces value under 1
std::cout << map4[true] << '\n'; // prints 'e'
std::vector<int> v{1, 2, 3};
find(begin(v), end(v), 2);
return 0;
}

View file

@ -0,0 +1,134 @@
#include <algorithm>
#include <iostream>
#include <type_traits>
#include <vector>
template <typename Key, typename Value>
class VectorMap {
std::vector<Key> keys_;
std::vector<Value> values_;
static_assert(std::is_default_constructible<Value>::value, "Value should have the default constructor");
static_assert(std::is_default_constructible_v<Value>, "Value should have the default constructor");
public:
using K = Key;
using V = Value;
template <typename T>
using iterator = typename std::vector<T>::iterator;
void insert(const Key& k, const Value& v) {
keys_.emplace_back(k);
values_.emplace_back(v);
}
static constexpr bool isIntKey() {
// if (std::is_integral_v<Key>) {
if (std::is_same_v<Key, int>) {
return true;
}
return false;
}
Value& operator[](const Key& k);
Value& at(const Key& k);
static constexpr bool is_int_key = std::is_same_v<Key, int>;
};
template <typename Key, typename Value>
Value& VectorMap<Key, Value>::operator[](const Key& k) {
auto it = std::find(std::begin(keys_), std::end(keys_), k);
if (it == std::end(keys_)) {
keys_.emplace_back(k);
values_.emplace_back(Value{});
return values_.back();
}
auto dist = std::distance(keys_.begin(), it);
return values_[dist];
}
template <typename Key, typename Value>
Value& VectorMap<Key, Value>::at(const Key& k) {
auto it = std::find(std::begin(keys_), std::end(keys_), k);
if (it == std::end(keys_)) {
throw std::out_of_range("This key does not exist");
}
auto dist = std::distance(keys_.begin(), it);
return values_[dist];
}
template <typename ValueType>
class VectorMap<bool, ValueType> { // specialization
static_assert(std::is_default_constructible<ValueType>::value,
"ValueType must have the default constructor");
ValueType t_;
ValueType f_;
public:
static constexpr bool is_int_key = false; // type_traits #2
VectorMap() {
std::cout << "bool specialization used\n";
}
void insert(bool key, ValueType&& value) {
if (key) {
t_ = value;
} else {
f_ = value;
}
}
ValueType& operator[](bool key) {
if (key) {
return t_;
}
return f_;
}
ValueType& at(bool key) {
if (key) {
return t_;
}
return f_;
}
};
template<typename T>
constexpr bool is_int_key_v = T::is_int_key;
template <typename Key, typename Value>
constexpr bool is_int_key_v1 = VectorMap<Key,Value>::is_int_key;
int main() {
VectorMap<int, char> map;
// VectorMap<int, char>::iterator<K> k;
map.insert(1, 'c');
std::cout << map[1] << '\n';
map[1] = 'e'; // replaces value under 1
std::cout << map[1] << '\n'; // prints 'e'
// map.at(2); // throw std::out_of_range
std::cout << std::boolalpha << map.isIntKey() << '\n';
std::cout << std::boolalpha << map.is_int_key << '\n';
VectorMap<char, char> map3;
std::cout << std::boolalpha << map3.isIntKey() << '\n';
VectorMap<bool, int> map4;
map4.insert(true, 3);
map4.insert(false, 0);
std::cout << map4[true] << '\n';
map4[true] = 10; // replaces value under 1
std::cout << map4[true] << '\n'; // prints 'e'
std::cout << std::boolalpha << is_int_key_v<decltype(map4)> << '\n';
std::cout << std::boolalpha << is_int_key_v<decltype(map)> << '\n';
std::cout << std::boolalpha << is_int_key_v<K> << '\n';
std::vector<int> v{1, 2, 3};
find(begin(v), end(v), 2);
return 0;
}

View file

@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.2)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
project(Resource)
set(SRC_LIST
resource.cpp
)
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_compile_options(${PROJECT_NAME} PUBLIC -Wall -Werror -Wpedantic -Wextra)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR})

View file

@ -0,0 +1,19 @@
## Linux compilation
> mkdir build
> cd build
> cmake -DCMAKE_BUILD_TYPE=Debug ..
> make
## Valgrind usage
> valgrind valgrind_params path/to/binary binary_params, eg:
> valgrind --leak-check=full ./Resource 5
> or full output using command: valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose --log-file=valgrind-out.txt ./Resource
## Resource exapmle
1. Compile and run Resource application and check memory leaks under valgrind
2. Fix memory leaks with a proper usage of delete operator
3. Refactor the solution to use `std::unique_ptr<>`
4. Use `std::make_unique`

View file

@ -0,0 +1,32 @@
#include <iostream>
#include <memory>
#include <stdexcept>
class Resource {
public:
void use(const char* N) {
std::cout << "Using resource. Passed " << *N << '\n';
if (*N == 'd') {
throw std::logic_error("Passed d. d is prohibited.");
}
};
};
int main(int argc, char* argv[]) {
if (argc != 2) {
std::cerr << "You need to pass 1 argument" << '\n';
exit(-1);
}
const char* arg = argv[1];
Resource* rsc = nullptr;
try {
rsc = new Resource();
rsc->use(arg);
delete rsc;
} catch (std::logic_error& e) {
std::cout << e.what() << '\n';
}
return 0;
}

View file

@ -0,0 +1,32 @@
#include <iostream>
#include <memory>
#include <stdexcept>
class Resource {
public:
void use(const char* N) {
std::cout << "Using resource. Passed " << *N << '\n';
if (*N == 'd') {
throw std::logic_error("Passed d. d is prohibited.");
}
};
};
int main(int argc, char* argv[]) {
if (argc != 2) {
std::cerr << "You need to pass 1 argument" << '\n';
exit(-1);
}
const char* arg = argv[1];
std::unique_ptr<Resource> rsc;
try {
rsc = std::make_unique<Resource>();
rsc->use(arg);
} catch (std::logic_error& e) {
}
return 0;
}

View file

@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.2)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
project(ResourceFactory)
set(SRC_LIST
resourceFactory.cpp
)
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_compile_options(${PROJECT_NAME} PUBLIC -Wall -Werror -Wpedantic -Wextra)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR})

View file

@ -0,0 +1,20 @@
## Linux compilation
> mkdir build
> cd build
> cmake -DCMAKE_BUILD_TYPE=Debug ..
> make
## Valgrind usage
> valgrind valgrind_params path/to/binary binary_params, eg:
> valgrind --leak-check=full ./ResourceFactory
> or full output using command: valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose --log-file=valgrind-out.txt ./ResourceFactory
## Resource exapmle
1. Compile and run ResourceFactory application
2. Put comments in places where you can spot some problems
3. How to remove elements from the collection (<code>vector&ltResource*&gt</code> resources)?
4. Check memory leaks
5. Fix problems

View file

@ -0,0 +1,65 @@
#include <iostream>
#include <vector>
#include <string>
struct Resource
{
Resource(char* byte) : byte_(byte) {}
char* byte() const { return byte_; }
virtual std::string name() const = 0;
~Resource() { delete byte_; }
protected:
char* byte_ = nullptr;
};
struct ResourceA : Resource
{
ResourceA(char* byte) : Resource(byte) {}
std::string name() const override { return std::string("ResourceA ").append(byte_); }
};
struct ResourceB : Resource
{
ResourceB(char* byte) : Resource(byte) {}
std::string name() const override { return std::string("ResourceB ").append(byte_); }
};
struct ResourceFactory
{
Resource* makeResourceA(char* byte) { return new ResourceA{byte}; }
Resource* makeResourceB(char* byte) { return new ResourceB{byte}; }
};
struct ResourceCollection
{
void add(Resource* r) { resources.push_back(r); }
void clear() { resources.clear(); }
Resource* operator[](int index) { return resources[index]; }
void printAll()
{
for (const auto & res : resources)
{
std::cout << res->name() << std::endl;
}
}
private:
std::vector<Resource*> resources;
};
int main()
{
ResourceCollection collection;
ResourceFactory rf;
collection.add(rf.makeResourceA(new char{91}));
collection.add(rf.makeResourceB(new char{92}));
collection.printAll();
auto firstByte = collection[0]->byte();
collection.clear();
std::cout << *firstByte << std::endl;
return 0;
}

View file

@ -0,0 +1,77 @@
#include <iostream>
#include <memory>
#include <string>
#include <utility>
#include <vector>
struct Resource {
Resource(std::unique_ptr<char> byte)
: byte_(std::move(byte)) {}
virtual ~Resource() = default;
// Rule of 5
char* byte() const { return byte_.get(); }
virtual std::string name() const = 0;
protected:
std::unique_ptr<char> byte_;
};
struct ResourceA : Resource {
~ResourceA() override {
std::cout << "ResourceA D'tor\n";
}
ResourceA(std::unique_ptr<char> byte)
: Resource(std::move(byte)) {}
std::string name() const override { return std::string("ResourceA ").append(1, *byte_); }
};
struct ResourceB : Resource {
~ResourceB() override {
std::cout << "ResourceB D'tor\n";
}
ResourceB(std::unique_ptr<char> byte)
: Resource(std::move(byte)) {}
std::string name() const override { return std::string("ResourceB ") + *byte_; }
};
struct ResourceFactory {
static std::unique_ptr<Resource> makeResourceA(std::unique_ptr<char> byte) {
return std::make_unique<ResourceA>(std::move(byte));
}
static std::unique_ptr<Resource> makeResourceB(std::unique_ptr<char> byte) {
return std::make_unique<ResourceB>(std::move(byte));
}
};
struct ResourceCollection {
void add(std::unique_ptr<Resource> r) { resources.push_back(std::move(r)); }
void clear() { resources.clear(); }
Resource* operator[](int index) const { return resources[index].get(); }
void printAll() const {
for (const auto& res : resources) {
std::cout << res->name() << '\n';
}
}
private:
std::vector<std::unique_ptr<Resource>> resources;
};
int main() {
ResourceCollection collection;
collection.add(ResourceFactory::makeResourceA(std::make_unique<char>(0x78)));
collection.add(ResourceFactory::makeResourceB(std::make_unique<char>(0x79)));
collection.printAll();
auto* firstByte = collection[0]->byte();
std::cout << *firstByte << '\n';
collection.clear();
// Use already free memory!
//std::cout << *firstByte << '\n';
return 0;
}

View file

@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.2)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
project(Searcher)
set(SRC_LIST
searcher.cpp
)
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_compile_options(${PROJECT_NAME} PUBLIC -Wall -Werror -Wpedantic -Wextra)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR})

View file

@ -0,0 +1,11 @@
## Linux compilation
> mkdir build
> cd build
> cmake -DCMAKE_BUILD_TYPE=Debug ..
> make
## Exercise
* Open project searcher
* Implement function `searchFiles` which returns all files containing `keyWord`.

View file

@ -0,0 +1 @@
Hello FileA

View file

@ -0,0 +1 @@
Hello FileA Ala ma kota

View file

@ -0,0 +1 @@
Hello FileB ALA

View file

@ -0,0 +1 @@
Hello FileB ala

View file

@ -0,0 +1 @@
Hello FileC ala kot i ala

View file

@ -0,0 +1 @@
Hello FileC ala kot i Ala i nie ma kota

View file

@ -0,0 +1,26 @@
#include <algorithm>
#include <concepts>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <iterator>
#include <ranges>
#include <string_view>
#include <vector>
namespace fs = std::filesystem;
namespace rn = std::ranges;
std::vector<fs::path> searchFiles(std::string_view keyWord, const fs::path& dirName) {
std::vector<fs::path> paths;
// Write implementation here
return paths;
}
int main() {
std::cout << "Files which contains word Ala:\n";
const auto& res = searchFiles("Ala", fs::current_path().string() + "/files");
rn::copy(res, std::ostream_iterator<fs::path>(std::cout, "\n"));
}

View file

@ -0,0 +1,37 @@
#include <algorithm>
#include <concepts>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <iterator>
#include <ranges>
#include <string_view>
#include <vector>
namespace fs = std::filesystem;
namespace rn = std::ranges;
std::vector<fs::path> searchFiles(std::string_view keyWord, const fs::path& dirName) {
std::vector<fs::path> paths;
rn::transform(fs::directory_iterator(dirName),
fs::directory_iterator{},
std::back_inserter(paths),
[](const auto& entry) { return entry.path(); });
std::vector<fs::path> res;
rn::copy_if(paths, std::back_inserter(res), [keyWord](const auto& path) {
std::ifstream file(path);
const auto end = std::istream_iterator<std::string>{};
return std::find_if(std::istream_iterator<std::string>(file),
end,
[keyWord](const auto& str) { return str == keyWord; }) != end;
});
return res;
}
int main() {
std::cout << "Files which contains word Ala:\n";
const auto& res = searchFiles("Ala", fs::current_path().string() + "/files");
rn::copy(res, std::ostream_iterator<fs::path>(std::cout, "\n"));
}

View file

@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.2)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
project(Someclass)
set(SRC_LIST
someclass.cpp
)
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_compile_options(${PROJECT_NAME} PUBLIC -Wall -Werror -Wpedantic -Wextra)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR})

View file

@ -0,0 +1,10 @@
## Linux compilation
> mkdir build
> cd build
> cmake -DCMAKE_BUILD_TYPE=Debug ..
> make
## Not exrecise
This is only example of template

View file

@ -0,0 +1,7 @@
#include <iostream>
int main() {
SomeClass<int, void> sc;
std::cout << sc.getValue() << std::endl;
return 0;
}

View file

@ -0,0 +1,16 @@
#include <iostream>
template <typename T, typename U>
class SomeClass {
public:
T getValue() { return value; }
private:
T value = {};
U* ptr = nullptr;
};
int main() {
SomeClass<int, void> sc;
std::cout << sc.getValue() << std::endl;
return 0;
}

View file

@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.2)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
project(Streamer)
set(SRC_LIST
streamer.cpp
)
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_compile_options(${PROJECT_NAME} PUBLIC -Wall -Werror -Wpedantic -Wextra)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR})

View file

@ -0,0 +1,31 @@
## Linux compilation
> mkdir build
> cd build
> cmake -DCMAKE_BUILD_TYPE=Debug ..
> make
## Exercise 1
* Open project streamer
* Add two C'tor:
* first will take initializer_list
* second const StreamInfo&
* initialize vector in initialization list
## Exercise 2
* Open project streamer
* Add aliases for ip adress, port and vlan.
## Exercise 3
* Open project streamer
* Create Streamer interface
* Allow to add data to stream
* Allow to add/remove receivers
* start/stop stream
* validate data
* Create Mpeg2Streamer class
* Create MjpegStreamer class
* Make some implementations that will allow to compile code

View file

@ -0,0 +1,29 @@
#include <iostream>
#include <vector>
class Streamer {
public:
struct StreamInfo {
std::string sourceAddress_;
std::string destinationAddress_;
uint16_t sourcePort_;
uint16_t destinationPort_;
uint16_t vlan_;
};
Streamer(std::initializer_list<StreamInfo> info)
: info_(info) {
}
Streamer(const StreamInfo& info)
: info_{info} {
}
private:
std::vector<StreamInfo> info_;
};
int main() {
Streamer streamer({"192.168.0.0", "192.168.10.24", 5432, 5432, 12});
Streamer streamer2{};
}

View file

@ -0,0 +1,71 @@
#include <iostream>
#include <vector>
template <typename Tag, typename T>
struct StrongAlias {
// Other C'tors, for r-value etc...
StrongAlias(const T& value)
: value_(value) {}
const T& operator*() const { return value_; }
T& operator*() { return value_; }
// Need to add hash function and operator<<
auto operator<=>(const StrongAlias& other) const = default;
private:
T value_;
};
using IpV4 = StrongAlias<class IpV4Tag, std::string>;
using IpV6 = StrongAlias<class IpV6Tag, std::string>;
using MacAddress = StrongAlias<class MacAddressTag, std::string>;
class Streamer {
public:
using IpAddress = std::string;
using Port = uint16_t;
using Vlan = uint16_t;
struct StreamInfo {
IpAddress sourceAddress_;
IpAddress destinationAddress_;
Port sourcePort_;
Port destinationPort_;
Vlan vlan_;
};
Streamer(std::initializer_list<StreamInfo> info)
: info_(info) {
}
Streamer(const StreamInfo& info)
: info_{info} {
}
private:
std::vector<StreamInfo> info_;
};
struct I {};
struct A : I {};
struct B : I {};
struct Foo {
Foo(I* inter): inter_(inter) {}
I* inter_;
}
int main() {
Streamer streamer({"192.168.0.0", "192.168.10.24", 5432, 5432, 12});
Streamer streamer2{};
IpV4 ip{"192.168.0.1"};
IpV4 ip2{"192.168.0.2"};
std::cout << std::boolalpha << (ip < ip2) << '\n';
std::cout << std::boolalpha << (ip > ip2) << '\n';
std::cout << std::boolalpha << (ip != ip2) << '\n';
std::cout << std::boolalpha << (ip == ip2) << '\n';
}

View file

@ -0,0 +1,23 @@
#include <iostream>
#include <vector>
class Streamer {
public:
struct StreamInfo {
std::string sourceAddress_;
std::string destinationAddress_;
uint16_t sourcePort_;
uint16_t destinationPort_;
uint16_t vlan_;
};
// Write C'tors here
private:
std::vector<StreamInfo> info_;
};
int main() {
Streamer streamer({"192.168.0.0", "192.168.10.24", 5432, 5432, 12});
Streamer streamer2{};
}

View file

@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.2)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
project(Students)
set(SRC_LIST
students.cpp
)
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_compile_options(${PROJECT_NAME} PUBLIC -Wall -Werror -Wpedantic -Wextra)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR})

View file

@ -0,0 +1,22 @@
## Linux compilation
> mkdir build
> cd build
> cmake -DCMAKE_BUILD_TYPE=Debug ..
> make
## Exercise
Open project `students`:
* implement function `filterStudents`,
* Student should be disqualified whether his average is below `minAvergae`,
* Write an algorithm that prints students using ranges (do not implement friend operator<<)
Output:
```C++
Name: Jane | index: 743561 | average: 4.44
Name: Tom | index: 811111 | average: 4.36
Name: Mike | index: 811111 | average: 4.45
```

View file

@ -0,0 +1,49 @@
#include <algorithm>
#include <iostream>
#include <iterator>
#include <memory>
#include <ranges>
#include <sstream>
#include <vector>
namespace rn = std::ranges;
struct Student {
int index_;
std::string name_;
double average_;
};
std::vector<Student*> filterStudents(const std::vector<std::unique_ptr<Student>>& students, double minAverage) {
std::vector<Student*> result;
rn::copy(students |
std::views::transform([](const auto& student) { return student.get(); }) |
std::views::filter([minAverage](const auto& student) { return student->average_ <= minAverage; }),
std::back_inserter(result));
return result;
}
int main() {
std::vector<std::unique_ptr<Student>> students;
students.push_back(std::make_unique<Student>(123456, "Jordan", 4.53));
students.push_back(std::make_unique<Student>(654321, "Michael", 4.51));
students.push_back(std::make_unique<Student>(246892, "John", 4.56));
students.push_back(std::make_unique<Student>(743561, "Jane", 4.44));
students.push_back(std::make_unique<Student>(811111, "Anna", 4.46));
students.push_back(std::make_unique<Student>(811111, "Tom", 4.36));
students.push_back(std::make_unique<Student>(811111, "Jerry", 4.56));
students.push_back(std::make_unique<Student>(811111, "Mike", 4.45));
const auto res = filterStudents(students, 4.45);
rn::transform(res,
std::ostream_iterator<std::string>(std::cout, "\n"),
[](const Student* student) {
std::ostringstream os;
os << "Name: " << student->name_
<< " | index: " << student->index_
<< " | average: " << student->average_;
return os.str();
});
}

View file

@ -0,0 +1,34 @@
#include <algorithm>
#include <iostream>
#include <iterator>
#include <memory>
#include <ranges>
#include <sstream>
#include <vector>
namespace rn = std::ranges;
struct Student {
int index_;
std::string name_;
double average_;
};
std::vector<Student*> filterStudents(const std::vector<std::unique_ptr<Student>>& students, double minAverage) {
// Implement method here
}
int main() {
std::vector<std::unique_ptr<Student>> students;
students.push_back(std::make_unique<Student>(123456, "Jordan", 4.53));
students.push_back(std::make_unique<Student>(654321, "Michael", 4.51));
students.push_back(std::make_unique<Student>(246892, "John", 4.56));
students.push_back(std::make_unique<Student>(743561, "Jane", 4.44));
students.push_back(std::make_unique<Student>(811111, "Anna", 4.46));
students.push_back(std::make_unique<Student>(811111, "Tom", 4.36));
students.push_back(std::make_unique<Student>(811111, "Jerry", 4.56));
students.push_back(std::make_unique<Student>(811111, "Mike", 4.45));
const auto res = filterStudents(students, 4.45);
// Print result here using ranges (do not create friend operator<<)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View file

@ -0,0 +1,236 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Advanced Cpp</title>
<link rel="stylesheet" href="../css/reset.css">
<link rel="stylesheet" href="../css/reveal.css">
<link rel="stylesheet" href="../css/theme/coders.css" id="theme">
<!-- Theme used for syntax highlighting of code -->
<link rel="stylesheet" href="../lib/css/monokai.css">
<!-- Printing and PDF exports -->
<script>
var link = document.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match(/print-pdf/gi) ? '../css/print/pdf.css' : '../css/print/paper.css';
document.getElementsByTagName('head')[0].appendChild(link);
</script>
</head>
<body>
<div class="reveal">
<div class="slides">
<section data-background="#fff">
<h1>Advanced Cpp</h1>
<br/>
<h3>Altkom Akademia</h3>
<a href="https://www.altkomakademia.pl">https://www.altkomakademia.pl</a>
<div class="multicolumn">
<div class="col">
<img data-src="../img/altkom_logo.png" alt="Altkom Akademia" class="plain" height="160px">
+48 801 258 566
</div>
<div class="col"></div>
<div class="col">
<img data-src="../img/altkom_logo2.png" alt="Altkom Akademia" class="plain" height="160px">
Mateusz Adamski
<a href="mailto:nauka.programowania.ma@gmail.com">nauka.programowania.ma@gmail.com</a>
</div>
</div>
</section>
<section data-markdown="introduction.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="agenda.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="compilation.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="moder_cpp_intro.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="moder_cpp_cpp11.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="moder_cpp_cpp14.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="moder_cpp_cpp17_intro.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="moder_cpp_cpp17_small_features.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="moder_cpp_cpp17_folding.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="moder_cpp_cpp17_constexpr.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="moder_cpp_cpp17_filesystem.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="moder_cpp_cpp20_intro.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="moder_cpp_cpp20_ranges.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="moder_cpp_cpp20_modules.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="moder_cpp_cpp20_small_features.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="smart_pointers_smart_ptrs.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="smart_pointers_unique_ptr.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="smart_pointers_shared_ptr.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="smart_pointers_weak_ptr.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="smart_pointers_auto_ptr.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="smart_pointers_summary.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="smart_pointers_best_practices.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="smart_pointers_implementation_details.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="smart_pointers_efficiency.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="templates_basic.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="templates_class.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="templates_typetraits.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="templates_specjalization.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="templates_partial_spec.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="templates_variable.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="template_deduction_guides.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-markdown="recap.md"
data-separator-vertical="^___"
data-separator-notes="^Note:">
</section>
<section data-background="#fff">
<h3>Altkom Akademia</h3>
<a href="https://www.altkomakademia.pl">https://www.altkomakademia.pl</a>
<br/><br/>
<div class="multicolumn">
<div class="col">
<div>
<img data-src="../img/altkom_logo.png" alt="altkomakademia" class="plain" height="150px">
<h6 style="color:black;font-size:24px;">
Zapraszamy do współpracy
ALTKOM AKADEMIA
ul. Chłodna 51, budynek WTT,
00-867 Warszawa
Telefon: (+48 22) 460 99 99,
Fax: (+48 22) 460 99 90
warszawa@altkom.pl
</h6>
</div>
</div>
<div class="col"></div>
<div class="col">
Mateusz Adamski
<a href="mailto:nauka.programowania.ma@gmail.com">nauka.programowania.ma@gmail.com</a>
</div>
</div>
</section>
</div>
</div>
<script src="../js/reveal.js"></script>
<script>
// More info about config & dependencies:
// - https://github.com/hakimel/reveal.js#configuration
// - https://github.com/hakimel/reveal.js#dependencies
Reveal.initialize({
width: 1200,
height: 750,
slideNumber: true,
hash: true,
pdfSeparateFragments: false,
dependencies: [
{ src: '../plugin/externalcode/externalcode.js', condition: function() { return !!document.querySelector( '[data-code]' ); } },
{ src: '../plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
{ src: '../plugin/markdown/marked.js' },
{ src: '../plugin/markdown/markdown.js' },
{ src: '../plugin/notes/notes.js', async: true }
]
});
</script>
</body>
</html>

View file

@ -0,0 +1,59 @@
<!-- .slide: data-background="#ccc" -->
<h2>Presentation authors</h2>
<div class="col">
<div class="row">
<img data-src="../img/mateusz.png" alt="Mateusz" class="plain" height="500px">
</div>
<div class="row">
Mateusz Adamski
</div>
</div>
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" style="font-size: 0.8em" -->
<h2>Mateusz Adamski</h2>
<div class="multicolumn">
<div class="col">
Experience:
* Trainer at Coders School and Altkom Academy
* C++ developer: worked in Nokia, Opera and Consult red
Training experience:
* [C++ trainings @ Coders School](https://coders.school/)
* [C++ trainings @ Altkom Academy](https://www.altkomakademia.pl/)
* [Nokia Academy](http://nokiawroclaw.pl/nasze-akcje/akademia/)
* Internal corporate trainings
</div>
<div class="col">
<img data-src="../img/mateusz.png" alt="Mateusz" class="plain" height="300px">
</div>
</div>
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Let's introduce yourself!
* <!-- .element: class="fragment fade-in" --> Your name and experience form C++ programing.
* <!-- .element: class="fragment fade-in" --> Do you use modern C++ features or prefer old old proven solutions?
* <!-- .element: class="fragment fade-in" --> Did you use any C++20 features?
* <!-- .element: class="fragment fade-in" --> Have you ever used weak_ptr, when?
* <!-- .element: class="fragment fade-in" --> Do you know how control block works?
* <!-- .element: class="fragment fade-in" --> What do you expect from today's session?
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Contract
* <!-- .element: class="fragment fade-in" --> 🎰 Vegas rule
* <!-- .element: class="fragment fade-in" --> 🗣 Discussion, not a lecture
* <!-- .element: class="fragment fade-in" --> ☕️ Additional breaks on demand
* <!-- .element: class="fragment fade-in" --> ⌚️ Be on time after breaks

View file

@ -0,0 +1,358 @@
## Cpp11
<!-- .slide: data-background="#ccc" -->
* <!-- .element: class="fragment fade-in" --> A quick reminder of lesser known features
* <!-- .element: class="fragment fade-in" --> static_assert
* <!-- .element: class="fragment fade-in" --> Uniform initialization
* <!-- .element: class="fragment fade-in" --> In-class initialization of non-static variables
* <!-- .element: class="fragment fade-in" --> initializer_list
* <!-- .element: class="fragment fade-in" --> alias
* <!-- .element: class="fragment fade-in" --> Template alias
* <!-- .element: class="fragment fade-in" --> C'tor inheritance
* <!-- .element: class="fragment fade-in" --> Attributes
* <!-- .element: class="fragment fade-in" --> Data structure alignment
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## static_assert
```cpp
template <class T>
void swap(T& a, T& b)
{
static_assert(std::is_copy_constructible<T>::value,
"Swap requires copying");
static_assert(std::is_nothrow_move_constructible_v<T> &&
std::is_nothrow_move_assignable_v<T>);
auto c = b;
b = a;
a = c;
}
```
<!-- .element: class="fragment fade-in" -->
**Rationale**: Preventing compilation on user defined conditions (usually specific types).
<!-- .element: class="fragment fade-in" -->
Performs compile-time assertion checking. Usually used with `<type_traits>` library.
<!-- .element: class="fragment fade-in" -->
The message is optional from C++17.
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.9em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## C++98/03 initialization
<pre><code class="cpp" data-trim data-line-numbers data-noescape>
int a; <span class="fragment">// undefined value </span>
int b(5); <span class="fragment">// direct initialization, b = 5 </span>
int c = 10; <span class="fragment">// copy initialization, c = 10 </span>
int d = int(); <span class="fragment">// default initialization, d = 0 </span>
int e(); <span class="fragment">// function declaration - "most vexing parse"</span>
int values[] = { 1, 2, 3, 4 }; <span class="fragment">// brace initialization of aggregate </span>
int array[] = { 1, 2, 3.5 }; <span class="fragment">// C++98 - ok, implicit type narrowing </span>
struct P { int a, b; }; <span> </span>
P p = { 20, 40 }; <span class="fragment">// brace initialization of POD </span>
std::complex&lt;double> c(4.0, 2.0); <span class="fragment">// initialization of classes </span>
std::vector&lt;std::string> names; <span class="fragment">// no initialization for list of values </span>
names.push_back("John"); <span> </span>
names.push_back("Jane"); <span> </span>
</code></pre>
<!-- .slide: style="font-size: 0.93em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## C++11 initialization with {}
<pre><code class="cpp" data-trim data-line-numbers data-noescape>
int a; <span class="fragment">// still undefined value </span>
int b{5}; <span class="fragment">// brace initialization, b = 5 </span>
int c{}; <span class="fragment">// brace initialization, c = 0 </span>
int values[] = { 1, 2, 3, 4 }; <span class="fragment">// brace initialization of aggregate </span>
int array[] = { 1, 2, 3.5 }; <span class="fragment">// C++11: error - implicit type narrowing </span>
struct P { int a, b;<span> </span>
P p = { 20, 40 }; <span class="fragment">// brace initialization of POD </span>
std::complex&lt;double> c{4.0, 2.0}; <span class="fragment">// brace initialization calls adequate c-tor</span>
std::vector&lt;std::string> names = { "John", "Jane" }; <span> </span>
<span class="fragment">// brace initialization of vector </span>
</code></pre>
**Rationale**: eliminate problematic initialization cases from C++98, initialization of STL containers, have one universal way of initialization.
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.90em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## In-class initialization of non-static variables
```cpp
struct Foo
{
Foo() {}
Foo(std::string a) : a_(a) {}
void print() { std::cout << a_ << std::endl; }
private:
std::string a_ = "Foo"; // C++98: error, C++11: OK
static const unsigned VALUE = 20u; // C++98: OK, C++11: OK
};
Foo().print(); // Foo
Foo("Bar").print(); // Bar
```
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## `std::initializer_list<T>`
```cpp
auto values = {1, 2, 3, 4, 5}; // values is std::initializer_list<int>
std::vector<int> v = {1, 2, -3}; // creates a vector from
// std::initializer_list<int>
```
* <!-- .element: class="fragment fade-in" --> Defined in <code>initializer_list</code> header
* <!-- .element: class="fragment fade-in" --> Elements are kept in an array
* <!-- .element: class="fragment fade-in" --> Elements are immutable
* <!-- .element: class="fragment fade-in" --> Elements must be copyable
* <!-- .element: class="fragment fade-in" --> Have limited interface and access via iterators - <code>begin()</code>, <code>end()</code>, <code>size()</code>
* <!-- .element: class="fragment fade-in" --> Should be passed to functions by value
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Constructor priority
<pre><code class="cpp" data-trim data-line-numbers data-noescape>
template&lt;class Type>
class Bar {
std::vector&lt;Type> values_;
public:
Bar(std::initializer_list&lt;Type> values) : values_(values) {}
Bar(Type a, Type b) : values_{a, b} {}
};
<span class="fragment">Bar&lt;int> c = {1, 2, 5, 51};</span> <span class="fragment">// calls std::initializer_list c-tor</span>
<span class="fragment">Bar&lt;int> d{1, 2, 5, 51};</span> <span class="fragment">// calls std::initializer_list c-tor</span>
<span class="fragment">Bar&lt;int> e = {1, 2};</span> <span class="fragment">// calls std::initializer_list c-tor</span>
<span class="fragment">Bar&lt;int> f{1, 2};</span> <span class="fragment">// calls std::initializer_list c-tor</span>
<span class="fragment">Bar&lt;int> g(1, 2);</span> <span class="fragment"> // calls Bar(Type a, Type b) c-tor </span>
<span class="fragment">Bar&lt;int> h = {};</span> <span class="fragment">// calls std::initializer_list c-tor</span>
<span class="fragment"> // or default c-tor if exists</span>
<span class="fragment">Bar&lt;std::unique_ptr<int>> c = {new int{1}, new int{2}}; </span>
<span class="fragment">// error - std::unique_ptr is non-copyable </span>
</code></pre>
C-tor with <code>std::initializer_list</code> has greater priority, even if other c-tors match.
<!-- .element: class="fragment fade-in" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Exercise 1
* <!-- .element: class="fragment fade-in" --> Open project streamer
* <!-- .element: class="fragment fade-in" --> Add two C'tor:
* <!-- .element: class="fragment fade-in" --> first will take <code>initializer_list</code>
* <!-- .element: class="fragment fade-in" --> second <code>const StreamInfo&</code>
* <!-- .element: class="fragment fade-in" --> initialize <code>vector</code> in <code><b>initialization</b> list</code>
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Type aliasing
```cpp
typedef std::ios_base::fmtflags Flags;
using Flags = std::ios_base::fmtflags; // the same as above
Flags fl = std::ios_base::dec;
```
<!-- .element: class="fragment fade-in" -->
```cpp
typedef std::vector<std::shared_ptr<Socket>> SocketContainer;
std::vector<std::shared_ptr<Socket>> typedef SocketContainer; // correct ;)
using SocketContainer = std::vector<std::shared_ptr<Socket>>;
```
<!-- .element: class="fragment fade-in" -->
**Rationale**: More intuitive alias creation.
<!-- .element: class="fragment fade-in" -->
A type alias is a name that refers to a previously defined type. It could be created with typedef.
From C++11 type aliases should be created with `using` keyword.
<!-- .element: class="fragment fade-in" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
### Template aliases
```cpp
struct ThemedLabelToogleButton { ... }
template <typename T>
using ButtonMap = std::map<ThemedLabelToogleButton, T>;
ButtonMap<std::function<void()>> my_map;
// std::map<ThemedLabelToogleButton, std::function<void()>
```
Type alias can be parametrized with templates. It was impossible with typedef.
<!-- .element: class="fragment fade-in" -->
Template aliases cannot be specialized.
<!-- .element: class="fragment fade-in" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
### Constructors inheritance
```cpp
struct A {
explicit A(int);
int a;
};
struct B : A {
using A::A; // implicit declaration of B::B(int)
B(int, int); // overloaded inherited Base ctor
};
```
* <!-- .element: class="fragment fade-in" --> Derived class constructors are generated implicitly, only if they are used
* <!-- .element: class="fragment fade-in" --> Derived class constructors take the same arguments as base class constructors
* <!-- .element: class="fragment fade-in" --> Derived class constructor calls according base class constructor
* <!-- .element: class="fragment fade-in" --> Constructor inheritance in a class that adds a new field might be risky - new fields can be uninitialized
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Exercise 2
* <!-- .element: class="fragment fade-in" --> Open project streamer
* <!-- .element: class="fragment fade-in" --> Add aliases for ip adress, port and vlan.
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Attributes
<!-- .slide: data-background="#ccc" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
### Standard attributes
* <!-- .element: class="fragment fade-in" --> <code>[[noreturn]]</code> - function does never return, like <code>std::terminate</code>. If it does, we have UB
* <!-- .element: class="fragment fade-in" --> <code>[[deprecated]]</code> (C++14) - function is deprecated
* <!-- .element: class="fragment fade-in" --> <code>[[deprecated("reason")]]</code> (C++14) - as above, but compiler will emit the reason
* <!-- .element: class="fragment fade-in" --> <code>[[fallthrough]]</code> (C++17) - in <code>switch</code> statement, indicated that fall through is intentional
* <!-- .element: class="fragment fade-in" --> <code>[[nodiscard]]</code> (C++17) - you cannot ignore value returned from function
* <!-- .element: class="fragment fade-in" --> <code>[[maybe_unused]]</code> (C++17) - suppress compiler warning on unused class, typedef, variable, function, etc.
<!-- Problem with backticks if fadeing inplemented like this -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## `[[noreturn]]` attribute
```c++
[[noreturn]] void f() {
throw "error";
// OK
}
[[noreturn]] void q(int i) {
if (i > 0) {
throw "positive";
}
// the behavior is undefined if called with argument <=0
}
```
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## `[[deprecated]] attribute`
Attributes for namespaces and enumerators are available from C++17.
```c++
[[deprecated("Please use f2 instead")]] int f1();
enum E {
foo = 0,
bar [[deprecated]] = foo
};
E e = bar; // Emits warning
namespace [[deprecated]] old_stuff {
void legacy();
}
old_stuff::legacy(); //Emits warning
```
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## `[[fallthrough]]` attribute
```c++
void f(int n){
void g(), h(), i();
switch(n) {
case 1:
case 2:
g();
[[fallthrough]];
case 3: // no warning on fallthrough
h();
case 4: // compiler may warn on fallthrough
i();
[[fallthrough]]; // illformed, not before a case label
}
}
```
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## `[[nodiscard]]` attribute
```c++
struct [[nodiscard]] error_info {};
error_info process(Data*);
// ...
void passMessage() {
auto data = getData();
process(data); // compiler warning, discarding error_info
}
```
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## `[[maybe_unused]]` attributes
```c++
[[maybe_unused]] void f([[maybe_unused]] bool thing1,
[[maybe_unused]] bool thing2)
{
[[maybe_unused]] bool b = thing1 && thing2;
assert (b); // in release mode, assert is compiled out, and b is unused
// no warning because it is declared [[maybe_unused]]
} // parameters thing1 and thing2 are not used, no warning
```

View file

@ -0,0 +1,256 @@
## Cpp14
<!-- .slide: data-background="#ccc" -->
* <!-- .element: class="fragment fade-in" --> A quick reminder of lesser known features
* <!-- .element: class="fragment fade-in" --> decltype(auto)
* <!-- .element: class="fragment fade-in" --> Variable templates
* <!-- .element: class="fragment fade-in" --> Binary literals (Finaly!)
* <!-- .element: class="fragment fade-in" --> Digit separators
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## `decltype`
**Rationale**: Deduction provided in contexts where auto is not allowed.
<!-- .element: class="fragment fade-in" -->
`decltype` allows a compiler to deduce the type of the variable or expression, eg. the returned type can be deduced from function parameters.
<!-- .element: class="fragment fade-in" -->
```cpp
std::map<std::string, float> collection;
decltype(collection) other; // other has type of collection
decltype(collection)::mapped_type value; // value is float
template <typename T1, typename T2>
auto add(T1 a, T2 b) -> decltype(a + b) // from C++14 decltype not necessary
{
return a + b;
}
```
<!-- .element: class="fragment fade-in" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
It is useful in various scenarios:
```C++
auto compare = [](const auto &first, const auto &second) {
if (first.size() == second.size()) {
return first < second;
}
return first.size() < second.size();
};
std::map<std::string, int, decltype(compare)> map(compare);
map.emplace("C++20", 20);
map.emplace("C++1234", 1234);
map.emplace("Bababab", 12);
map.emplace("Abababa", 13);
for (const auto &[standard, number] : map) {
std::cout << "Standard: " << standard << " | number: " << number << '\n';
/* Output:
Standard: C++20 | number: 20
Standard: Abababa | number: 13
Standard: Bababab | number: 12
Standard: C++1234 | number: 1234 */
}
```
<!-- .slide: style="font-size: 0.90em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
Since C++20 we can use lambda expressions in unevaluated operands:
```C++
using SquareRoot = decltype([](const int val) {
return std::sqrt(val);
});
using Compare = decltype([](const auto &first, const auto &second) {
if (first.size() == second.size()) {
return first < second;
}
return first.size() < second.size();
});
int main() {
std::vector<int> vec(30);
std::iota(begin(vec), end(vec), 0);
std::transform(begin(vec), end(vec), begin(vec), SquareRoot{});
for (const auto& el : vec) {
std::cout << el << ' ';
}
// Output:
// 0 1 1 1 2 2 2 2 2 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 5 5 5 5 5
// Compare lambda will be constructed by default
std::map<std::string, int, Compare> map;
map.emplace("C++20", 20);
map.emplace("C++1234", 1234);
map.emplace("Bababab", 12);
map.emplace("Abababa", 13);
}
```
Closure types are not default constructible before C++20. In C++20 a closure type that has no capture is default constructible. That's why we can do a litle magic here :)
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.70em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## `decltype(auto)`
`decltype(auto)` deduction mechanism preserves type modifiers (references, const, volatile).
<!-- .element: class="fragment fade-in" -->
`auto` deduction mechanism does not preserve type modifiers.
<!-- .element: class="fragment fade-in" -->
When you write generic code you want to be able to perfectly forward a return type without knowing whether you are dealing with a reference or a value.
<!-- .element: class="fragment fade-in" -->
```cpp
template<typename Fun, class... Args>
decltype(auto) Example(Fun fun, Args&&... args)
{
return fun(std::forward<Args>(args)...);
}
```
<!-- .element: class="fragment fade-in" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Let's test it
We have the following class:
```C++
class Server {
public:
bool addRequest(const std::string& serviceId, const std::string& request) {
return requests_.emplace(serviceId, request).second;
}
std::string& getRequest(const std::string& serviceId) {
if (const auto it = requests_.find(serviceId) ; it != std::cend(requests_)) {
return it->second;
}
throw std::runtime_error("Invalid serviceId");
}
private:
std::map<std::string, std::string> requests_;
};
int main() {
Server server;
server.addRequest("SuperService", "Eat meat first!");
server.getRequest("SuperService") += " Leave the potatoes";
std::cout << server.getRequest("SuperService") << '\n';
// Eat meat first! Leave the potatoes
}
```
<!-- .slide: style="font-size: 0.74em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
Now let's use it with generic function, but without `decltype(auto)`
```C++
template<typename Fun, class... Args>
auto RunFun(Fun fun, Args&&... args)
{
return fun(std::forward<Args>(args)...);
}
int main() {
Server server;
server.addRequest("SuperService", "Eat meat first!");
// Write that we want to return std::string&
RunFun([&server](const auto& id) -> std::string& { return server.getRequest(id); },
"SuperService") += " Leave the potatoes";
std::cout << server.getRequest("SuperService") << '\n';
// Output: Eat meat first!
// Compiler didn't emit any warning!
}
```
<!-- .slide: style="font-size: 0.80em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
Now fix this with `decltype(auto)`
```C++
template<typename Fun, class... Args>
decltype(auto) RunFun(Fun fun, Args&&... args)
{
return fun(std::forward<Args>(args)...);
}
int main() {
Server server;
server.addRequest("SuperService", "Eat meat first!");
// Write that we want to return std::string&
RunFun([&server](const auto& id) -> std::string& { return server.getRequest(id); },
"SuperService") += " Leave the potatoes";
std::cout << server.getRequest("SuperService") << '\n';
// Output: Eat meat first! Leave the potatoes
}
```
Now we avoid misleading and don't waste time on debugging sessions!
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.80em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Variable templates
```C++
template <typename T>
constexpr T pi = T(3.141592653589793238462643383);
// Usual specialization rules apply:
template <>
constexpr const char* pi<const char*> = "pi";
template <>
constexpr const int pi<const int> = 4;
int main() {
std::cout << pi<double> << '\n'; // 3.14159
std::cout << pi<const char*> << '\n'; // pi
std::cout << pi<int> << '\n'; // 3
std::cout << pi<const int> << '\n'; // 4
return 0;
}
```
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Binary literals
```C++
int main() {
std::cout << 0b10101010 << '\n'; // 170
const int val = 0b1111;
std::cout << (val ^ 0b1010) << '\n'; // 5
return 0;
}
```
<!-- .element: class="fragment fade-in" -->
## Digit separators
<!-- .element: class="fragment fade-in" -->
```C++
const int milion = 1'000'000;
const double val = 123'456'789'101.000;
```
<!-- .element: class="fragment fade-in" -->

View file

@ -0,0 +1,425 @@
## constexpr - one of the most undervalued feature in modern C++ (1)
* <!-- .element: class="fragment fade-in" --> <code>constexpr</code> was introduced in C++11
* <!-- .element: class="fragment fade-in" --> constexpr values are know during compilation process
* <!-- .element: class="fragment fade-in" --> Function also could be constexpr with some restriction:
* <!-- .element: class="fragment fade-in" --> they may only have exactly one statement and this statement had to be a return statement
* <!-- .element: class="fragment fade-in" --> not allowed to have any side effects, like if-else
* <!-- .element: class="fragment fade-in" --> not allowed to have exception and try-catch block
* <!-- .element: class="fragment fade-in" --> can use ternary operator
* <!-- .element: class="fragment fade-in" --> Usually wrote recurent rather then iterative functions
* <!-- .element: class="fragment fade-in" --> Functions behave like normal functions (not solved during compilation) when working with non-constexpr arguments
* <!-- .element: class="fragment fade-in" --> Class/ struct could have constexpr C'tor and member functions
* <!-- .element: class="fragment fade-in" --> In C++14 introduced:
* <!-- .element: class="fragment fade-in" --> <b>Less restrictions for functions</b>:
* <!-- .element: class="fragment fade-in" --> more then one return
* <!-- .element: class="fragment fade-in" --> can use if-else
___
### constexpr - one of the most undervalued feature in modern C++ (2)
* <!-- .element: class="fragment fade-in" --> In C++17 introduced:
* <!-- .element: class="fragment fade-in" --> constexpr class string_view
* <!-- .element: class="fragment fade-in" --> <b>constexpr std::array</b>
* <!-- .element: class="fragment fade-in" --> constexpr iterator for array and std::begin, std::end functions
* <!-- .element: class="fragment fade-in" --> <b>constexpr lambda</b>
* <!-- .element: class="fragment fade-in" --> In C++20 introduced:
* <!-- .element: class="fragment fade-in" --> <b>constexpr STL algorithms</b>
* <!-- .element: class="fragment fade-in" --> <b>constexpr std::vector and std::string</b> and their iterators. (not supported by clang and gcc. Surprisely its supported by MSVC STL)
* <!-- .element: class="fragment fade-in" --> Allow to use try-catch in constexpr functions
* <!-- .element: class="fragment fade-in" --> Allow to allocate and deallocate values on heap, but need to free them before exit function
* <!-- .element: class="fragment fade-in" --> Allow to create virtual functions
* <!-- .element: class="fragment fade-in" --> Allow to use asm code block
___
## C++11 constexpr function
```C++
#include <cstddef>
constexpr bool isLower(char c) {
return c >= 'a' && c <= 'z';
}
template <typename T, size_t N>
constexpr size_t countLower(const T (&str)[N], size_t current, size_t counter) {
return current == N
? counter
: isLower(str[current])
? countLower(str, current + 1, counter + 1)
: countLower(str, current + 1, counter);
}
int main() {
static_assert(9 == countLower("Ala has a cat", 0, 0));
}
```
<!-- .element: class="fragment fade-in" -->
```Bash
xor eax,eax
ret
nop WORD PTR cs:[rax+rax*1+0x0]
nop DWORD PTR [rax]
```
<!-- .element: class="fragment fade-in" -->
<style>
div {text-align: center;}
</style>
<div>check on <a href="https://godbolt.org/">https://godbolt.org/</a></div>
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.75em" -->
___
## C++14 constexpr function
```C++
constexpr bool isLower(char c) {
return c >= 'a' && c <= 'z';
}
template <typename T, size_t N>
constexpr size_t countLower(const T (&str)[N]) {
size_t counter = 0;
for (auto c : str) {
if (isLower(c)) {
++counter;
}
}
return counter;
}
int main() {
static_assert(9 == countLower("Ala has a cat"));
}
```
<!-- .element: class="fragment fade-in" -->
```Bash
xor eax,eax
ret
nop WORD PTR cs:[rax+rax*1+0x0]
nop DWORD PTR [rax]
```
<!-- .element: class="fragment fade-in" -->
<style>
div {text-align: center;}
</style>
<div>check on <a href="https://godbolt.org/">https://godbolt.org/</a></div>
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.75em" -->
___
## C++17 constexpr function (1)
```C++
template <typename T, size_t N>
constexpr size_t countLower(const T (&str)[N]) {
constexpr auto isLower = [](char c) { return c >= 'a' && c <= 'z'; };
size_t counter = 0;
for (auto c : str) {
if (isLower(c)) {
++counter;
}
}
return counter;
}
int main() {
static_assert(9 == countLower("Ala has a cat"));
}
```
<!-- .element: class="fragment fade-in" -->
```Bash
xor eax,eax
ret
nop WORD PTR cs:[rax+rax*1+0x0]
nop DWORD PTR [rax]
```
<!-- .element: class="fragment fade-in" -->
<style>
div {text-align: center;}
</style>
<div>check on <a href="https://godbolt.org/">https://godbolt.org/</a></div>
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.75em" -->
___
## C++17 constexpr function (2)
```C++
constexpr size_t countLower(const std::string_view& str) {
constexpr auto isLower = [](char c) { return c >= 'a' && c <= 'z'; };
size_t counter = 0;
for (size_t i = 0 ; i < str.size() ; ++i) {
if (isLower(str[i])) {
++counter;
}
}
return counter;
}
int main() {
static_assert(9 == countLower("Ala has a cat"));
}
```
<!-- .element: class="fragment fade-in" -->
```Bash
xor eax,eax
ret
cs nop WORD PTR [rax+rax*1+0x0]
nop DWORD PTR [rax]
```
<!-- .element: class="fragment fade-in" -->
<style>
div {text-align: center;}
</style>
<div>check on <a href="https://godbolt.org/">https://godbolt.org/</a></div>
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.75em" -->
___
## C++20 constexpr function
```C++
constexpr size_t countLower(const std::string& str) {
constexpr auto isLower = [](char c) { return c >= 'a' && c <= 'z'; };
size_t counter = 0;
for (size_t i = 0 ; i < str.size() ; ++i) {
if (isLower(str[i])) {
++counter;
}
}
return counter;
}
int main() {
static_assert(9 == countLower(std::string("Ala has a cat")));
}
```
<style>
div {text-align: center;}
</style>
<div>check on <a href="https://en.cppreference.com/w/cpp/compiler_support">https://en.cppreference.com/w/cpp/compiler_support</a></div>
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.75em" -->
___
## C++20 constexpr function - algorithms
```C++
constexpr size_t countLower(const std::string& str) {
constexpr auto isLower = [](char c) { return c >= 'a' && c <= 'z'; };
return std::count_if(cbegin(str), cend(str), isLower);
}
int main() {
static_assert(9 == countLower(std::string("Ala has a cat")));
}
```
<style>
div {text-align: center;}
</style>
<div>check on <a href="https://en.cppreference.com/w/cpp/compiler_support">https://en.cppreference.com/w/cpp/compiler_support</a></div>
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.75em" -->
___
## C++20 constexpr - allocation on heap (1)
```C++
template <typename T, size_t N>
constexpr std::array<T, N> generatePseudoRandom(int from, int to) {
std::array<T, N> arr;
const int seed = ((N << 1) ^ (from << to) ^ to) ^ ((from + to) ^ (N << 3));
const size_t size = to - from;
auto tmp = new int[size];
std::iota(tmp, tmp + size, from);
for (int i = 0; i < N; ++i) {
arr[i] = tmp[(seed ^ i) % size];
}
delete[] tmp;
return arr;
}
int main() {
static_assert(generatePseudoRandom<int, 10>(10, 20).size() == 10);
}
```
<!-- .element: class="fragment fade-in" -->
```C++
Will print: 18 19 16 17 14 15 12 13 10 11
```
<!-- .element: class="fragment fade-in" -->
```Bash
xor eax,eax
ret
cs nop WORD PTR [rax+rax*1+0x0]
nop DWORD PTR [rax]
```
<!-- .element: class="fragment fade-in" -->
<style>
div {text-align: center;}
</style>
<div>check on <a href="https://godbolt.org/">https://godbolt.org/</a></div>
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.68em" -->
___
## C++20 constexpr - allocation on heap (1)
If we forget to add <code>delete[]</code>, compiler will detect it!
```C++
template <typename T, size_t N>
constexpr std::array<T, N> generatePseudoRandom(int from, int to) {
std::array<T, N> arr;
const int seed = ((N << 1) ^ (from << to) ^ to) ^ ((from + to) ^ (N << 3));
const size_t size = to - from;
auto tmp = new int[size];
std::iota(tmp, tmp + size, from);
for (int i = 0; i < N; ++i) {
arr[i] = tmp[(seed ^ i) % size];
}
//delete[] tmp;
return arr;
}
int main() {
static_assert(generatePseudoRandom<int, 10>(10, 20).size() == 10);
}
```
<!-- .element: class="fragment fade-in" -->
```C++
<source>: In function 'int main()':
<source>:22:64: error: non-constant condition for static assertion
22 | static_assert(generatePseudoRandom<int, 10>(10, 20).size() == 10);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~
<source>:10:16: error: '(generatePseudoRandom<int, 10>(10, 20).std::array<int, 10>::size() == 10)' is not a constant expression because allocated storage has not been deallocated
10 | auto tmp = new int[size];
| ^~~~~~~~~~~~~
Execution build compiler returned: 1
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.62em" -->
___
### contexpr-if (1)
* <!-- .element: class="fragment fade-in" --> Who uses SFINAE?
* <!-- .element: class="fragment fade-in" --> Who likes SFINAE?
```C++
namespace {
constexpr double epsilon = 0.000001;
}
template <class T>
constexpr std::enable_if_t<std::is_floating_point_v<T>, bool>
equal(T lhs, T rhs) {
return std::abs(lhs - rhs) < epsilon;
}
template <class T>
constexpr std::enable_if_t<!std::is_floating_point_v<T>, bool>
equal(T lhs, T rhs) {
return lhs == rhs;
}
int main() {
static_assert(equal(10, 10) == true);
static_assert(equal(10.123f, 10.123f) == true);
static_assert(equal(10.45678, 10.45678) == true);
}
```
<!-- .element: class="fragment fade-in" -->
```C++
xor eax,eax
ret
cs nop WORD PTR [rax+rax*1+0x0]
nop DWORD PTR [rax]
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.62em" -->
___
### contexpr-if (2)
```C++
template <typename T>
constexpr bool equal(T lhs, T rhs) {
constexpr double epsilon = 0.000001;
if constexpr (std::is_floating_point_v<T>) {
return std::abs(lhs - rhs) < epsilon;
} else {
return lhs == rhs;
}
}
int main() {
static_assert(equal(10, 10) == true);
static_assert(equal(10.123f, 10.123f) == true);
static_assert(equal(10.45678, 10.45678) == true);
}
```
<!-- .element: class="fragment fade-in" -->
```C++
xor eax,eax
ret
cs nop WORD PTR [rax+rax*1+0x0]
nop DWORD PTR [rax]
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.62em" -->
___
### C++20 concept
```C++
template <typename T>
requires std::is_floating_point_v<T>
constexpr bool equal(T lhs, T rhs) {
constexpr double epsilon = 0.000001;
return std::abs(lhs - rhs) < epsilon;
}
// Work only, when both types are equal!
constexpr bool equal(auto lhs, auto rhs) {
return lhs == rhs;
}
int main() {
static_assert(equal(10, 10) == true);
static_assert(equal(10.123f, 10.123f) == true);
static_assert(equal(10.45678, 10.45678) == true);
}
```
<!-- .element: class="fragment fade-in" -->
```C++
xor eax,eax
ret
cs nop WORD PTR [rax+rax*1+0x0]
nop DWORD PTR [rax]
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.62em" -->

View file

@ -0,0 +1,341 @@
## Filesystem
<!-- .slide: data-background="#ccc" -->
Since C++17 we can efficiently work with the file systems on all OS like Mac, Windows, and various Linux distributions.
```C++
namespace fs = std::filesystem;
void printStatsForDirectory(const fs::path& dir_path) {
std::cout << "Statistics:\n";
std::cout << ".cpp files: "
<< std::count_if(fs::recursive_directory_iterator(dir_path), {},
[](const auto& entry) {
return entry.is_regular_file() && entry.path().extension() == ".cpp";
}) << '\n';
std::cout << ".md files: "
<< std::count_if(fs::recursive_directory_iterator(dir_path), {},
[](const auto& entry) {
return entry.is_regular_file() && entry.path().extension() == ".md";
}) << '\n';
std::cout << ".h files: "
<< std::count_if(fs::recursive_directory_iterator(dir_path), {},
[](const auto& entry) {
return entry.is_regular_file() && entry.path().extension() == ".h";
}) << '\n';
std::cout << "Total size: "
<< (std::accumulate(fs::recursive_directory_iterator(dir_path), {}, 0,
[](const auto& init, const auto& entry) {
return init + (entry.is_regular_file() ? entry.file_size() : 0);
}) >> 20) << " MB\n";
}
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.75em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Output
```C++
int main() {
const auto path{fs::current_path()};
std::cout << "current path: " << path << '\n';
const auto path2 = path.parent_path().parent_path();
std::cout << "path2: " << path2 << '\n';
printStatsForDirectory(path2);
}
```
```bash
current path: "C:\\Users\\madamski\\Documents\\altcom_academy\\Nokia2022\\Advanced\\Course_part1\\exercises\\streamer"
path2: "C:\\Users\\madamski\\Documents\\altcom_academy\\Nokia2022\\Advanced\\Course_part1"
Statistics:
.cpp files: 16
.md files: 53
.h files: 47
Total size: 103 MB
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.75em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Info about system space
```C++
void printSpaceInfo(auto const& dirs, int width = 10) {
std::cout << std::left;
for (const auto s : {"Capacity", "Free", "Available", "Dir"}) {
std::cout << "| " << std::setw(width) << s << std::string(3, ' ');
}
std::cout << '\n';
for (auto const& dir : dirs) {
const auto info = fs::space(dir);
std::cout
<< "| " << std::setw(width) << (info.capacity >> 30) << " GB"
<< "| " << std::setw(width) << (info.free >> 30) << " GB"
<< "| " << std::setw(width) << (info.available >> 30) << " GB"
<< "| " << dir << '\n';
}
}
int main() {
const auto dirs = {"C:\\", "D:\\", "E:\\"};
printSpaceInfo(dirs);
/*
| Capacity | Free | Available | Dir
| 237 GB| 15 GB| 15 GB| C:\
| 383 GB| 179 GB| 179 GB| D:\
| 463 GB| 220 GB| 220 GB| E:\
*/
}
```
<!-- .slide: style="font-size: 0.72em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Permissions
```C++
void printPerms(fs::perms p) {
std::cout << ((p & fs::perms::owner_read) != fs::perms::none ? "r" : "-")
<< ((p & fs::perms::owner_write) != fs::perms::none ? "w" : "-")
<< ((p & fs::perms::owner_exec) != fs::perms::none ? "x" : "-")
<< ((p & fs::perms::group_read) != fs::perms::none ? "r" : "-")
<< ((p & fs::perms::group_write) != fs::perms::none ? "w" : "-")
<< ((p & fs::perms::group_exec) != fs::perms::none ? "x" : "-")
<< ((p & fs::perms::others_read) != fs::perms::none ? "r" : "-")
<< ((p & fs::perms::others_write) != fs::perms::none ? "w" : "-")
<< ((p & fs::perms::others_exec) != fs::perms::none ? "x" : "-")
<< '\n';
}
int main() {
for (const auto& entry : fs::directory_iterator(fs::current_path())) {
if (fs::is_regular_file(entry.path())) {
std::cout << "File: "
<< std::left << std::setw(20)
<< entry.path().filename()
<< " | Permissions: ";
printPerms(fs::status(entry.path()).permissions());
}
}
/*
File: "CMakeLists.txt" | Permissions: rw-rw-rw-
File: "example.exe" | Permissions: rwxrwxrwx
File: "README.md" | Permissions: rw-rw-rw-
File: "streamer.cpp" | Permissions: rw-rw-rw-
*/
}
```
<!-- .slide: style="font-size: 0.72em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Exercise
Open project `files`. Write a program which modify files under `project` directory:
- Change permision for all .exe files to `rwxrw-rw-`.
- Change permision for all .cpp and .hpp files to `rw-r--r--`.
You should get output like this:
<!-- .element: class="fragment fade-in" -->
```Bash
File: "fileA.cpp" | Permissions: rw-------
File: "fileA.hpp" | Permissions: rw-------
File: "fileB.cpp" | Permissions: rw-------
File: "fileB.hpp" | Permissions: rw-------
File: "fileC.cpp" | Permissions: rw-------
File: "fileC.hpp" | Permissions: rw-------
File: "project.exe" | Permissions: rw-------
File: "fileA.cpp" | Permissions: rw-r--r--
File: "fileA.hpp" | Permissions: rw-r--r--
File: "fileB.cpp" | Permissions: rw-r--r--
File: "fileB.hpp" | Permissions: rw-r--r--
File: "fileC.cpp" | Permissions: rw-r--r--
File: "fileC.hpp" | Permissions: rw-r--r--
File: "project.exe" | Permissions: rwxrw-rw-
```
<!-- .slide: style="font-size: 0.78em" -->
<!-- .element: class="fragment fade-in" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Exercise 2
Open project `files`. Modify `FileB` by append any word. Now write a program which:
- return last modify files
- return a vector with 3 files that were longest unmodified.
Expected result (path may by different):
<!-- .element: class="fragment fade-in" -->
```Bash
Last modified file is: "/home/runner/SilentSiennaModularity/files/project/fileB.cpp"
File write time is Sat May 14 17:56:18 2022
files that were longest unmodified:
File: "/home/runner/SilentSiennaModularity/files/project/fileA.cpp" | last modify time: Sat May 14 16:43:33 2022
File: "/home/runner/SilentSiennaModularity/files/project/fileA.hpp" | last modify time: Sat May 14 16:43:33 2022
File: "/home/runner/SilentSiennaModularity/files/project/fileB.hpp" | last modify time: Sat May 14 16:43:33 2022
```
<!-- .element: class="fragment fade-in" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Problems and fixes
- <!-- .element: class="fragment fade-in" --> Remember that <code>recursive_directory_iterator</code> and <code>directory_iterator</code> are <code>InputIterator</code>. If you move iterator to the next position you invalidate all reference to previous object. If you need to use algorithm which demand <code>ForwardIterator</code> you can copy all paths to separate container
- <!-- .element: class="fragment fade-in" --> If you want to keep sorted files inside <code>set</code> or <code>map</code> you should check whether their modification times are the same. If true you need to compare their names or files with the same modification time will be lost.
- <!-- .element: class="fragment fade-in" --> Setup premissions for files works only on Linux/ MacOS system. This is caused by different type of File system. Windows file system mainly NTFS do not support priviliges like in other systems eg. EXT4. There are still properites but handled in different way:
- <!-- .element: class="fragment fade-in" --> Full Control: Grants complete access, including the ability to see, read, write, execute and delete files or folders, as well as change permission settings for all subdirectories.
- <!-- .element: class="fragment fade-in" --> Modify: The user can see, read, execute, write and delete files. Also allows for the deletion of the folder itself.
- <!-- .element: class="fragment fade-in" --> Read & Execute: Can view folder contents and run programs or scripts.
- <!-- .element: class="fragment fade-in" --> List folder contents: Allows the user to see files and directories contained within a folder, an important setting for navigating to deeper levels in the folder structure.
- <!-- .element: class="fragment fade-in" --> Read: Can see folder contents and also view the files and folders in question.
- <!-- .element: class="fragment fade-in" --> Write: Users can add new files and folders and write to existing files.
- <!-- .element: class="fragment fade-in" --> Special permissions: Additional permissions available through the Advanced Security Settings in the Windows file system. Includes options such as Read Attributes, Create Files or Traverse Folder.
<!-- .slide: style="font-size: 0.86em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Temporary files for testing
Sometimes during a test we need to read input data from file. usually we need to create this file and attach to test directory. But since C++17 we can easily use temporary directory to create all files. let's test this class: (The main resposibility is to queued all files and stream them)
```C++
class Streamer {
public:
Streamer() = default;
virtual ~Streamer() = default;
Streamer(const Streamer&) = default;
Streamer(Streamer&&) = default;
Streamer& operator=(const Streamer&) = default;
Streamer& operator=(Streamer&&) = default;
virtual void stream() = 0;
virtual void stop() = 0;
};
```
___
<!-- .slide: data-background="#ccc" -->
<div class="multicolumn">
<div class="col">
```C++
class MpgegStreamer : public Streamer {
public:
MpgegStreamer(const fs::path& path)
: path_(path) {
for (int i = 0; i < 4; ++i) {
workers_.emplace_back(&MpgegStreamer::work, this, i);
}
}
~MpgegStreamer() override {
for (auto& th : workers_) {
th.join();
}
}
void stream() override {
for (const auto& entry : fs::directory_iterator(path_)) {
std::lock_guard lg(m_);
streamQueue_.push(entry.path());
}
}
virtual void stop() {
finishAction_ = true;
}
```
</div>
<div class="col">
```C++
private:
void work(int id) {
while (!finishAction_) {
fs::path path;
{
std::lock_guard lg(m_);
// Ofc this will be better with condition variable
if (streamQueue_.empty()) {
continue;
}
path = std::move(streamQueue_.front());
streamQueue_.pop();
}
stream(path, id);
}
}
void stream(const fs::path path, int id) const {
std::fstream fileToStream(path);
std::transform(
std::istream_iterator<std::string>(fileToStream),
{},
std::ostream_iterator<std::string>(std::cout),
[id](const std::string& str) {
std::stringstream ss;
ss << "Streamer: " << id << " | data: " << str << '\n';
return ss.str();
});
}
mutable std::mutex m_;
std::vector<std::thread> workers_;
std::queue<fs::path> streamQueue_;
fs::path path_;
std::atomic<bool> finishAction_{false};
};
```
</div>
</div>
<!-- .slide: style="font-size: 0.52em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
We can create temporary direcotories (yes we can create them recursive!) and cleanup at the end. We don't need to be afraid of removing sth neccessary because we will work only with tmoprary directories.
```C++
int main() {
const auto tmp_path = fs::temp_directory_path();
const auto mpegDir = tmp_path.string() + "Test/MpgegFiles";
const auto mp4Dir = tmp_path.string() + "Test/MP4Files";
// Create test directory
fs::create_directories(mpegDir);
fs::create_directory(mp4Dir);
// Add files
for (int i = 0; i < 10; ++i) {
std::ofstream file(mpegDir + "/File" + std::to_string(i));
file << "this is some text in the new file\n" << i;
}
for (int i = 0; i < 10; ++i) {
std::ofstream file(mp4Dir + "/File" + std::to_string(i));
file << "this is some text in the new file\n" << i;
}
std::cout << "Start streaming" << std::endl;
std::unique_ptr<Streamer> streamer = std::make_unique<MpgegStreamer>(mpegDir);
streamer->stream();
std::this_thread::sleep_for(std::chrono::seconds(1));
streamer->stop();
fs::remove_all(tmp_path.string() + "Test");
}
```
<!-- .slide: style="font-size: 0.70em" -->

View file

@ -0,0 +1,280 @@
## Fold expressions
* <!-- .element: class="fragment fade-in" --> Folding is a new way of handling argument package
* <!-- .element: class="fragment fade-in" --> It can be one or two arguments
* <!-- .element: class="fragment fade-in" --> If it is two arguments we distinguish between
* <!-- .element: class="fragment fade-in" --> left folding
* <!-- .element: class="fragment fade-in" --> right folding
___
### Fold expressions - adding values
```C++
template <typename... Args>
int add(Args... args) {
return (args + ...);
}
int main() {
std::cout << add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) << '\n';
std::cout << add() << '\n'; // Not compile!
}
```
<!-- .element: class="fragment fade-in" -->
```C++
55
```
<!-- .element: class="fragment fade-in" -->
___
### Fold expressions - adding values
```C++
template <typename... Args>
int add(Args... args) {
return (args + ... + 0);
}
int main() {
std::cout << add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) << '\n';
std::cout << add() << '\n'; // OK
}
```
<!-- .element: class="fragment fade-in" -->
```C++
55
0
```
<!-- .element: class="fragment fade-in" -->
___
### Fold expressions - subtracting values
```C++
template <typename... Args>
int subR(Args... args) {
return (args - ...);
}
template <typename... Args>
int subL(Args... args) {
return (... - args);
}
int main() {
// (1 - 2)
std::cout << subR(1, 2) << '\n'; // -1
// (1 - 2)
std::cout << subL(1, 2) << '\n'; // -1
// (1 - (2 - 3))
std::cout << subR(1, 2, 3) << '\n'; // 2
// ((1 - 2) - 3)
std::cout << subL(1, 2, 3) << '\n'; // -4
// (1 - (2 - (3 - 4)))
std::cout << subR(1, 2, 3, 4) << '\n'; // -2
// (((1 - 2) - 3) - 4)
std::cout << subL(1, 2, 3, 4) << '\n'; // -8
// (1 - (2 - (3 - (4 - 5))))
std::cout << subR(1, 2, 3, 4, 5) << '\n'; // 3
// ((((1 - 2) - 3) - 4) - 5)
std::cout << subL(1, 2, 3, 4, 5) << '\n'; // -13
}
```
<!-- .slide: style="font-size: 0.69em" -->
___
### Fold expressions - make code work without parameters
Find a problem with the below code.
<!-- .element: class="fragment fade-in" -->
```C++
template <typename... Args>
int subR(Args... args) {
return (args - ... - 0);
}
template <typename... Args>
int subL(Args... args) {
// What's wrong here???
return (0 - ... - args);
}
int main() {
// (1 - (2 - (3 - (4 - 5))))
std::cout << subR(1, 2, 3, 4, 5) << '\n';
// ((((1 - 2) - 3) - 4) - 5)
std::cout << subL(1, 2, 3, 4, 5) << '\n';
std::cout << subR() << '\n';
std::cout << subL() << '\n';
}
```
<!-- .element: class="fragment fade-in" -->
```C++
3 // (1 - (2 - (3 - (4 - (5 - 0))))
-15 // (((((0 - 1) - 2) - 3) - 4) - 5)
0
0
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.75em" -->
___
## How to demand minimum one variable
```C++
template<typename Value, typename... Values>
auto average(Value const& value, Values const&... values)
{
return (value + ... + values) / (1. + sizeof...(values));
}
int main() {
std::cout << average(1, 2, 3, 4) << '\n'; // print 2.5
std::cout << average() << '\n' // NOT COMPILE!
}
```
___
## Calling member functions
```C++
template<typename... Args>
void loggStateForAll(const Args&... args)
{
(..., args.loggState());
}
struct A {
void loggState() const {
std::cout << "StateA: good!\n";
}
};
struct B {
void loggState() const {
std::cout << "StateB: bad!\n";
}
};
int main() {
loggStateForAll(A{}, B{}, A{}, B{});
/* Will print
StateA: good!
StateB: bad!
StateA: good!
StateB: bad! */
}
```
<!-- .slide: style="font-size: 0.74em" -->
___
## Fold expressions - insert to container (1)
```C++
class Foo {
public:
Foo(int num)
: num_(num) {}
int num() const { return num_; }
private:
int num_;
};
template <typename... Args>
void emplaceAll(std::vector<Foo>& vec, Args... args) {
(vec.emplace_back(args), ...);
}
int main() {
std::vector<Foo> vec;
emplaceAll(vec, 1, 2, 3, 4, 5, 6, 7);
std::transform(cbegin(vec), cend(vec), std::ostream_iterator<int>(std::cout, " "),
[](const auto& foo) { return foo.num(); });
}
```
<!-- .element: class="fragment fade-in" -->
```C++
1 2 3 4 5 6 7
```
<!-- .element: class="fragment fade-in" -->
* <b>What with <code>(..., vec.emplace_back(args))</code>?</b>
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.73em" -->
___
### Fold expressions - insert to container (2)
* <!-- .element: class="fragment fade-in" --> There is no right/left type of folding for one type of argument
* <!-- .element: class="fragment fade-in" --> Unary right fold (fun(arg0) , (fun(arg1) , (fun(arg2) , ...)))
* <!-- .element: class="fragment fade-in" --> Unary left fold (((fun(arg0) , fun(arg1)) , fun(arg2)) , ...
* <!-- .element: class="fragment fade-in" --> Only for binary folding, we can have different behavior
___
### Fold expressions - logic operators
```C++
template <typename... Args>
bool emplaceAll(std::set<int>& set, Args... args) {
return (set.insert(args).second && ...);
}
int main() {
std::set<int> set;
emplaceAll(set, 1, 2, 3, 4, 5, 1, 6, 7);
std::copy(cbegin(set), cend(set), std::ostream_iterator<int>(std::cout, " "));
}
```
<!-- .element: class="fragment fade-in" -->
```C++
1 2 3 4 5
```
<!-- .element: class="fragment fade-in" -->
<b>For bot way:</b>
<code>return (set.insert(args).second && ...);</code>
<!-- .element: class="fragment fade-in" -->
<b>and</b>
<code>return (... && set.insert(args).second);</code>
<b>output will be the same</b>
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.90em" -->
___
### Fold expressions - cooperation with STL algorithms
```C++
template <typename... Args>
bool HasAll(const std::vector<int>& vec, Args... args) {
return ((std::find(cbegin(vec), cend(vec), args) != std::cend(vec)) && ...);
}
int main() {
std::vector<int> vec{1, 2, 3, 4, 1, 2, 3, 5, 6, 7, 4};
std::cout << std::boolalpha << HasAll(vec, 2, 4, 6) << '\n';
std::cout << std::boolalpha << HasAll(vec, 2, 4, 6, 8) << '\n';
}
```
<!-- .element: class="fragment fade-in" -->
```C++
true
false
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.8em" -->

View file

@ -0,0 +1,11 @@
## Cpp17
* <!-- .element: class="fragment fade-in" --> A quick reminder of lesser known features
* <!-- .element: class="fragment fade-in" --> Nested namespace definitions
* <!-- .element: class="fragment fade-in" --> Class template argument deduction
* <!-- .element: class="fragment fade-in" --> Selection statements with initializer
* <!-- .element: class="fragment fade-in" --> Unified initialization
* <!-- .element: class="fragment fade-in" --> Structural biding
* <!-- .element: class="fragment fade-in" --> Fold expressions
* <!-- .element: class="fragment fade-in" --> Constexpr
* <!-- .element: class="fragment fade-in" --> Filesystem

View file

@ -0,0 +1,244 @@
## Nested namespace definitions
<!-- .slide: data-background="#ccc" -->
You can nest namespaces like this:
<!-- .element: class="fragment fade-in" -->
```c++
namespace A::B::C {
...
}
```
<!-- .element: class="fragment fade-in" -->
Instead of this:
<!-- .element: class="fragment fade-in" -->
```c++
namespace A {
namespace B {
namespace C {
...
}
}
}
```
<!-- .element: class="fragment fade-in" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Class template argument deduction
From C++17 class template arguments can be deduced automatically. Automatic template argument deduction was available earlier only for template functions.
```c++
std::pair p(1, 'x'); // C++17: OK, C++14: error: missing.
// std::pair<int, char>
std::pair<int, std::string> p(1, "x"); // C++14: OK
// std::pair<int, std::string>
auto p2 = std::make_pair(1, "x"); // C++17: OK, C++14: OK (but not string!)
// std::pair<int, const char*>
std::pair p3(1, "x"); // C++17: OK (but not string!), C++14 error
```
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Selection statements with initializer (1)
New versions of the `if` and `switch` statements for C++:
<!-- .element: class="fragment fade-in" -->
### `if (init; condition)`
<!-- .element: class="fragment fade-in" -->
```cpp
status_code foo() { // C++14
{ //variable c scope
status_code c = bar();
if (c != SUCCESS) {
return c;
}
}
// ...
}
```
<!-- .element: class="fragment fade-in" -->
```cpp
status_code foo() { // C++17
if (status_code c = bar(); c != SUCCESS) {
return c;
}
// ...
}
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.8em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Selection statements with initializer (2)
### `switch (init; condition)`
<!-- .element: class="fragment fade-in" -->
```C++
class Foo {
public:
enum class ErrorCode {
Ok,
Bad,
VeryBad
};
ErrorCode doSth() {}
}
int main() {
switch (Foo foo ; const auto err = foo.doSth()) {
case ErrorCode::Ok:
break;
case ErrorCode::Bad:
break;
case ErrorCode::VeryBad:
break;
}
}
```
<!-- .slide: style="font-size: 0.85em" -->
<!-- .element: class="fragment fade-in" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Selection statements with initializer (3)
```C++
class ThreadSafeQueue {
public:
std::optional<int> try_pop() {
int val = 0;
// Lock guard is visible inside if-else
if (std::lock_guard lock(m_) ; queue_.empty()) {
return {};
} else {
val = queue_.front();
queue_.pop();
}
// Here mutex is no longer locked
logger << "pop value from queue";
return val;
}
private:
std::queue<int> queue_;
std::mutex m_;
};
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.92em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Hiding variable inside <code>if-else</code> statement (2)
We can avoid assigning iterators and then comapre it in `if` statement. Now we can write it faster
```C++
int main() {
std::vector<int> vec;
if (const auto it = std::find(std::cbegin(vec), std::cend(vec), 10) ; it != std::cend(vec)) {
// *it* is visible here
} else {
// and here
}
// but not here
std::map<std::string, int>
if (const auto it = map.find("Ala") ; it != std::cend(map)) {
// ...
} else {
// ...
}
}
```
<!-- .slide: style="font-size: 0.79em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Unified initialization
* <!-- .element: class="fragment fade-in" --> C++11 introduce <code>{}</code> for initialization
* <!-- .element: class="fragment fade-in" --> C++17 fixed some problems with <code>{}</code> and unified it.
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Unified initialization C++11
* Guess output (compiler 4.7.4 with C++11 flag)
<pre><code class="cpp" data-trim data-line-numbers data-noescape>
auto a {1}; <span class="fragment">//std::initializer_list&lt;int></span>
auto b = {1}; <span class="fragment">//std::initializer_list&lt;int></span>
auto c {1, 2}; <span class="fragment">//std::initializer_list&lt;int></span>
auto d = {1, 2}; <span class="fragment">//std::initializer_list&lt;int></span>
auto e = {1, 2, 3.f}; <span class="fragment">//Not compile </span>
auto f {1, 2, 3.f} <span class="fragment">//Not compile </span>
</code></pre>
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Unified initialization C++17
* Guess output (compiler 8.4 with C++17 flag)
<pre><code class="cpp" data-trim data-line-numbers data-noescape>
auto a {1}; <span class="fragment">//int </span>
auto b = {1}; <span class="fragment">//std::initializer_list&lt;int></span>
auto c {1, 2}; <span class="fragment">//Not compile (mising =) </span>
auto d = {1, 2}; <span class="fragment">//std::initializer_list&lt;int></span>
auto e = {1, 2, 3.f}; <span class="fragment">//Not compile </span>
auto f {1, 2, 3.f} <span class="fragment">//Not compile </span>
</code></pre>
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Structural biding
* <!-- .element: class="fragment fade-in" --> Unpack strucures, classes, tuples, pairs etc...
```C++
struct Foo{};
std::tuple<int, std::string, Foo> getTuple() {
return {5, "Ala has a cat", Foo{}};
}
struct Bar {
std::string str_;
double val_;
char c_;
std::vector<int> vec_;
};
int main() {
const auto& [id, topic, foo] = getTuple();
std::vector<Bar> bar;
for (const auto& [name, value, sign, vec] : bar) {
// ...
}
std::map<int, std::string> map;
for (const auto& [key, value] : map) {
// ..
}
};
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.70em" -->

View file

@ -0,0 +1,15 @@
## Cpp20
<!-- .slide: data-background="#ccc" -->
- <!-- .element: class="fragment fade-in" --> ranges
- <!-- .element: class="fragment fade-in" --> modules
- <!-- .element: class="fragment fade-in" --> operator<=>,
- <!-- .element: class="fragment fade-in" --> designated initializers,
- <!-- .element: class="fragment fade-in" --> atributes
- <!-- .element: class="fragment fade-in" --> pack-expansion in lmabdas (how to avoid copy)
- <!-- .element: class="fragment fade-in" --> template syntax for lambdas
- <!-- .element: class="fragment fade-in" --> uniform erasure
- <!-- .element: class="fragment fade-in" --> How to log useful informations in fast way using C++20 (source_loaction), subtitution for old macros.
- <!-- .element: class="fragment fade-in" --> bit operations
- <!-- .element: class="fragment fade-in" --> format your string like in <code>printf</code>
<!-- .slide: style="font-size: 0.80em" -->

View file

@ -0,0 +1,142 @@
## Modules
<!-- .slide: data-background="#ccc" -->
Legacy `includes` system form `C` language finally was replaced in C++20 by modules. `include` is actually 50 years old!
New keywords:
<!-- .element: class="fragment fade-in" -->
* <!-- .element: class="fragment fade-in" --> <code>Export</code>
* <!-- .element: class="fragment fade-in" --> <code>Import</code>
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Less code in binary
<div class="multicolumn">
<div class="col">
```C++
#include <iostream>
int main() {
std::cout << "Hello World!\n";
}
```
```C++
g++ -std=c++2b -E main.cpp | wc -c
929065
```
</div>
<!-- .element: class="fragment fade-in" -->
<div class="col">
```C++
import <iostream>;
int main() {
std::cout << "Hello Modular World!\n";
}
```
```C++
g++ -std=c++2b -fmodules-ts main.cpp | wc -c
239
```
</div>
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.88em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Export
Modules provide better encapsulation because you can export only those methods, which you mark as exported. The rest of the functions stay hidden outside the file.
```C++
// calculator.cc
export module Calculator;
export auto add(auto x, auto y) {
return x + y;
}
export auto substract(auto x, auto y) {
return x - y;
}
export namespace Advanced {
auto factorial(auto x) {
decltype(x) res = 1;
for (int i = 2 ; i <= x ; ++i) {
res *= i
}
return res;
}
}
void this_function_will_not_be_exported() {}
// main.cc
import <iostream>;
import Calculator;
int main() {
std::cout << "10 + 20 = " << add(10, 20) << '\n';
std::cout << "40 - 60 = " << substract(40, 60) << '\n';
std::cout << "5! = " << Advanced::factorial(5) << '\n';
// this_function_will_not_be_exported -> compile error
}
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.57em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## spread modules across multiple files
Only one file can be `interface` and `export` module. Other files can write implementations.
```C++
// interface.cc
export module calculator
export {
auto add(auto x, auto y);
auto substract(auto x, auto y);
}
// add.cc
module calculator
auto add(auto x, auto y) {
return x + y;
}
// substract.cc
module calculator
auto substract(auto x, auto y) {
return x - y;
}
// main.cc
import <iostream>;
import calculator;
int main() {
std::cout << "10 + 20 = " << add(10, 20) << '\n';
std::cout << "40 - 60 = " << substract(40, 60) << '\n';
}
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.64em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Compiler and Cmake supoort
Unfortunately when we want to build binary with modules using g++ or clang even when we have the newest version (on 17.05.2022 there is g++ 13 and clang 15) we still have partial support for modules. It will takes a few years before we will start using this in customer projects. Currently, even CMake(3.23.1) Didn't fully support modules: (https://gitlab.kitware.com/cmake/cmake/-/issues/18355).
<!-- .slide: style="font-size: 0.90em" -->

View file

@ -0,0 +1,396 @@
## Ranges
<!-- .slide: data-background="#ccc" -->
Let's start with simple example:
```C++
int main() {
auto const ints = {0, 1, 2, 3, 4, 5};
auto even = [](int i) { return 0 == i % 2; };
auto square = [](int i) { return i * i; };
for (int i : ints | std::views::filter(even) | std::views::transform(square)) {
std::cout << i << ' ';
}
}
```
<!-- .element: class="fragment fade-in" -->
```C++
0 4 16
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.93em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## New iterators
* <!-- .element: class="fragment fade-in" --> <code>std::ranges::input_range</code>: specifies a range whose iterator type satisfies input_iterator (can iterate from begin to end at least once)
* <!-- .element: class="fragment fade-in" --> <code>std::ranges::output_range</code>: specifies a range whose iterator type satisfies output_iterator
* <!-- .element: class="fragment fade-in" --> <code>std::ranges::forward_range</code>: specifies a range whose iterator type satisfies forward_iterator (can iterate from begin to end more than once)
* <!-- .element: class="fragment fade-in" --> <code>std::ranges::bidirectional_range</code>: specifies a range whose iterator type satisfies bidirectional_iterator (can iterate forward and backward more than once)
* <!-- .element: class="fragment fade-in" --> <code>std::ranges::random_access_range</code>: specifies a range whose iterator type satisfies random_access_iterator (can jump in constant time to an arbitrary element with the index operator [])
* <!-- .element: class="fragment fade-in" --> <code>std::ranges::contiguous_range</code>: specifies a range whose iterator type satisfies contiguous_iterator (elements are stored consecutively in memory)
<!-- .slide: style="font-size: 0.95em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Improvements for iterators
Whenever we iterate through value, we need to check if we reach the end. But We can provide an optimization, which avoids comparing `it != end`. We can do this by passing `std::unreachable_sentinel`. This sentinel always returns `false` when compared, that's why the compiler can optimize the process. **but be careful** if you provide wrong input, like searching numbers which don't exist in acontainer you got `Segmentation fault`.
```C++
int main() {
std::vector<int> vec = { 1, 2, 3, 4, 5, 6, 7, 8, 9};
std::ranges::shuffle(vec, std::mt19937(std::random_device()()));
std::cout << *std::ranges::find(vec.begin(), std::unreachable_sentinel, 5) << '\n';
// change this for 10 and you got Segmentation fault
}
```
<!-- .slide: style="font-size: 0.95em" -->
see <a href="https://eel.is/c++draft/unreachable.sentinel">unreachable.sentinel</a>
<!-- .element: class="fragment fade-in" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## More improvements - predicates
Whenever you wanted to sort structure based on the class member you need to provide a special comparator:
```C++
struct Student {
int index_;
std::string name_;
double average_;
};
int main() {
std::vector<Student> students{{.index_ = 123456, .name_ = "Jordan", .average_ = 4.53},
{.index_ = 654321, .name_ = "Michael", .average_ = 4.51},
{.index_ = 246892, .name_ = "John", .average_ = 4.56},
{.index_ = 743561, .name_ = "Jane", .average_ = 4.44},
{.index_ = 811111, .name_ = "Anna", .average_ = 4.46}};
std::sort(begin(students), end(students), [](const auto& lhs, const auto& rhs){
return lhs.average_ < rhs.average_;
});
for (const auto& [index, name, average] : students) {
std::cout << "student: " << name << " | index: " << index << " | avergae: " << average << '\n';
}
/* student: Jane | index: 743561 | avergae: 4.44
student: Anna | index: 811111 | avergae: 4.46
student: Michael | index: 654321 | avergae: 4.51
student: Jordan | index: 123456 | avergae: 4.53
student: John | index: 246892 | avergae: 4.56 */
}
```
<!-- .slide: style="font-size: 0.74em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
Now you can write it much faster!:
```C++
struct Student {
int index_;
std::string name_;
double average_;
};
int main() {
std::vector<Student> students{{.index_ = 123456, .name_ = "Jordan", .average_ = 4.53},
{.index_ = 654321, .name_ = "Michael", .average_ = 4.51},
{.index_ = 246892, .name_ = "John", .average_ = 4.56},
{.index_ = 743561, .name_ = "Jane", .average_ = 4.44},
{.index_ = 811111, .name_ = "Anna", .average_ = 4.46}};
// container, comparator, projection
std::ranges::sort(students, {}, &Student::average_);
for (const auto& [index, name, average] : students) {
std::cout << "student: " << name << " | index: " << index << " | avergae: " << average << '\n';
}
}
```
<!-- .slide: style="font-size: 0.80em" -->
All magic is done by the new parameter `projection`. It points to address to member and use it to provide a comparison: `std::invoke(comp, std::invoke(proj, *(it + n)), std::invoke(proj, *it))`
<!-- .element: class="fragment fade-in" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## View
Here is a quote from Eric Nieblers range-v3 implementation which is the base for the C++20 ranges: "Views are composable adaptations of ranges where the adaptation happens lazily as the view is iterated." In other words: `view` is not an owner of range. So we don't need to copy/move elements, only perform some action. Only exception is a `std::views::single` which owns the single element it is viewing.
<!-- .element: class="fragment fade-in" -->
Let's use `Foo` which prints whenever we create/ copy/ move or delete him.
<!-- .element: class="fragment fade-in" -->
<div class="multicolumn">
<div class="col">
```C++
int main() {
auto even = [](const auto& el) { return !(el.id() % 2); };
std::vector<Foo> vec {Foo{1}, Foo{2}, Foo{3}, Foo{4}};
std::cout << "Start algorithm\n";
for (const auto& foo : vec
| std::views::filter(even)
| std::views::drop_while([](const auto& el){ return el.id() < 4; })) {
std::cout << "foo: " << foo << '\n';
}
}
```
We don't make any copy!
</div>
<!-- .element: class="fragment fade-in" -->
<div class="col">
```C++
C'tor id: 1
C'tor id: 2
C'tor id: 3
C'tor id: 4
Copy C'tor id: 1
Copy C'tor id: 2
Copy C'tor id: 3
Copy C'tor id: 4
D'tor id:4
D'tor id:3
D'tor id:2
D'tor id:1
Start algorithm
foo: 4
D'tor id:1
D'tor id:2
D'tor id:3
D'tor id:4
```
</div>
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.74em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## View (2)
This is also usefull to create `range loop` which iterate reversed:
```C++
int main() {
std::vector<Student> students{{.index_ = 123456, .name_ = "Jordan", .average_ = 4.53},
{.index_ = 654321, .name_ = "Michael", .average_ = 4.51},
{.index_ = 246892, .name_ = "John", .average_ = 4.56},
{.index_ = 743561, .name_ = "Jane", .average_ = 4.44},
{.index_ = 811111, .name_ = "Anna", .average_ = 4.46}};
std::ranges::sort(students, {}, &Student::average_);
for (const auto& [index, name, average] : std::views::reverse(students)) {
std::cout << "student: " << name << " | index: " << index << " | avergae: " << average << '\n';
}
/*
student: John | index: 246892 | avergae: 4.56
student: Jordan | index: 123456 | avergae: 4.53
student: Michael | index: 654321 | avergae: 4.51
student: Anna | index: 811111 | avergae: 4.46
student: Jane | index: 743561 | avergae: 4.44
*/
}
```
<!-- .slide: style="font-size: 0.80em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## View (3)
We can also create `range loop` which iterates only through the first/last `k` elements:
```C++
int main() {
std::vector<Student> students{{.index_ = 123456, .name_ = "Jordan", .average_ = 4.53},
{.index_ = 654321, .name_ = "Michael", .average_ = 4.51},
{.index_ = 246892, .name_ = "John", .average_ = 4.56},
{.index_ = 743561, .name_ = "Jane", .average_ = 4.44},
{.index_ = 811111, .name_ = "Anna", .average_ = 4.46}};
std::ranges::sort(students, {}, &Student::average_);
for (const auto& [index, name, average] : std::views::reverse(students) | std::views::drop(3)) {
std::cout << "student: " << name << " | index: " << index << " | avergae: " << average << '\n';
}
/* student: Anna | index: 811111 | avergae: 4.46
student: Jane | index: 743561 | avergae: 4.44 */
for (const auto& [index, name, average] : std::views::reverse(students) | std::views::take(3)) {
std::cout << "student: " << name << " | index: " << index << " | avergae: " << average << '\n';
}
/* student: John | index: 246892 | avergae: 4.56
student: Jordan | index: 123456 | avergae: 4.53
student: Michael | index: 654321 | avergae: 4.51 */
}
```
<!-- .slide: style="font-size: 0.80em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## std::map
```C++
int main() {
std::map<int, std::string> map{{1, "One"}, {2, "Two"}, {3, "Three"}, {4, "Four"}};
auto odd = [](const auto& el) { return el % 2; };
for (auto el : std::views::keys(map) | std::views::filter(odd)) {
std::cout << el << ' ';
}
std::cout << '\n';
for (const char c : map | std::views::values | std::views::join) {
std::cout << c << ' ';
}
}
```
<!-- .element: class="fragment fade-in" -->
```C++
1 3
O n e T w o T h r e e F o u r
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.74em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## C++23 and further
Ranges library based on `Ranges V3`. Unfortunately, in C++20 there is a lack of useful things like creating cycles or zip functions. In C++23 there will be a few more operations like `zip` or `join_with`:
```C++
int main() {
auto x = std::vector{1, 2, 3, 4};
auto y = std::list<std::string>{"α", "β", "γ", "δ", "ε"};
auto z = std::array{'A', 'B', 'C', 'D', 'E', 'F'};
/* 1 α A
2 β B
3 γ C
4 δ D */
for (const auto& [num, grec, alpha] : std::views::zip(x, y, z)) {
std::cout << num << ' ' << grec << ' ' << alpha << '\n';
}
std::map<int, std::string> map{{1, "One"}, {2, "Two"}, {3, "Three"}, {4, "Four"}};
auto ends_with_e = [](const auto& el) { return el.back() == 'e'; };
const auto joined = std::views::values(map) | std::views::filter(ends_with_e) | std::views::join_with(' ');
/* Two Four */
for (const auto& el : joined) {
std::cout << el;
}
}
```
<!-- .slide: style="font-size: 0.74em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## actions (C++23)
There is a proposal to extend ranges in C++23 to allow easy convert range to container (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1206r6.pdf)
```C++
int main() {
std::map<int, std::string> map{
{1, "Hello"}, {2, "Abcd"}, {3, "Hello"}, {4, "Aaa"}, {5, "Ala"}, {6, "Abcd"}};
// Since C++23
for (const auto& el : map
| std::views::values
| std::ranges::to<std::vector> // Since C++23
| std::ranges::sort
| std::ranges::unique) {
std::cout << el << '\n';
}
}
```
```C++
Aaa
Abcd
Ala
Hello
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.88em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## actions (C++26)
In C+26 we should get also `operator|=`.
<div>
Before C++26
```C++
int main() {
std::vector<std::string> vec{"Hello", "Abcd", "Hello", "Aaa", "Ala", "Abcd"};
std::ranges::sort(vec);
auto ret = std::ranges::unique(vec);
vec.erase(ret.begin(), ret.end());
}
```
</div>
<!-- .element: class="fragment fade-in" -->
<div>
In C++26
```C++
int main() {
std::vector<std::string> vec{"Hello","Abcd", "Hello", "Aaa", "Ala", "Abcd"};
vec |= std::ranges::sort | std::ranges::unique;
}
```
</div>
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.88em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Exercise 1
Open project `searcher` and implement function `searchFiles` which returns all files containing `keyWord`.
Possible output:
<!-- .element: class="fragment fade-in" -->
```C++
"C:\\Users\\mateusz\\Documents\\Nokia2022\\Basic\\Course_part1\\exercises\\searcher/files\\fileA.hpp"
"C:\\Users\\mateusz\\Documents\\Nokia2022\\Basic\\Course_part1\\exercises\\searcher/files\\fileC.hpp"
```
<!-- .element: class="fragment fade-in" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Exercise 2
Open project `students`:
* implement function `filterStudents`,
* Student should be disqualified whether his average is below `minAvergae`,
* Write an algorithm that prints students using ranges (do not implement friend operator<<)
Output:
<!-- .element: class="fragment fade-in" -->
```C++
Name: Jane | index: 743561 | average: 4.44
Name: Tom | index: 811111 | average: 4.36
Name: Mike | index: 811111 | average: 4.45
```
<!-- .element: class="fragment fade-in" -->

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,39 @@
# Timeline of C++ (1)
<!-- .slide: data-background="#ccc" -->
* <!-- .element: class="fragment fade-in" --> C++98:
* <!-- .element: class="fragment fade-in" --> Templates
* <!-- .element: class="fragment fade-in" --> I/O streams
* <!-- .element: class="fragment fade-in" --> String
* <!-- .element: class="fragment fade-in" --> STL containers, iterators, algorithms
* <!-- .element: class="fragment fade-in" --> C++11:
* <!-- .element: class="fragment fade-in" --> Smart pointers
* <!-- .element: class="fragment fade-in" --> Move semantic
* <!-- .element: class="fragment fade-in" --> Lambda expressions
* <!-- .element: class="fragment fade-in" --> Unified initialization
* <!-- .element: class="fragment fade-in" --> Auto deduction
* <!-- .element: class="fragment fade-in" --> Constexpr
* <!-- .element: class="fragment fade-in" --> Multithreading and new model of memory
* <!-- .element: class="fragment fade-in" --> Regular expressions
* <!-- .element: class="fragment fade-in" --> Hash tables
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Timeline of C++ (2)
* <!-- .element: class="fragment fade-in" --> C++14:
* <!-- .element: class="fragment fade-in" --> Generic lambda
* <!-- .element: class="fragment fade-in" --> Reader-write lock
* <!-- .element: class="fragment fade-in" --> C++17:
* <!-- .element: class="fragment fade-in" --> Parallel algorithms
* <!-- .element: class="fragment fade-in" --> Filesystem library
* <!-- .element: class="fragment fade-in" --> Fold expression
* <!-- .element: class="fragment fade-in" --> constexpr if
* <!-- .element: class="fragment fade-in" --> Structural binding
* <!-- .element: class="fragment fade-in" --> any/ optional/ variant
* <!-- .element: class="fragment fade-in" --> C++20:
* <!-- .element: class="fragment fade-in" --> Modules
* <!-- .element: class="fragment fade-in" --> Concepts
* <!-- .element: class="fragment fade-in" --> Ranges
* <!-- .element: class="fragment fade-in" --> Coroutines
* <!-- .element: class="fragment fade-in" --> Other small features :)

View file

@ -0,0 +1,8 @@
<!-- .slide: data-background="#ccc" -->
# Recap
___
<!-- .slide: data-background="#ccc" -->
## What do you remember from today's session?

View file

@ -0,0 +1,10 @@
<!-- .slide: data-background="#ccc" -->
## `std::auto_ptr<>` - something to forget
* <!-- .element: class="fragment fade-in" --> C++98 provided <code>std::auto_ptr<></code>
* <!-- .element: class="fragment fade-in" --> Few fixes in C++03
* <!-- .element: class="fragment fade-in" --> Yet still its easy to use incorrectly…
* <!-- .element: class="fragment fade-in" --> Deprecated since C++11
* <!-- .element: class="fragment fade-in" --> Removed since C++17
* <!-- .element: class="fragment fade-in" --> Do not use it, use <code>std::unique_ptr<></code> instead

View file

@ -0,0 +1,196 @@
<!-- .slide: data-background="#ccc" -->
# Best practices
___
## Best practices
* <!-- .element: class="fragment fade-in" --> Rule of 0, Rule of 5
* <!-- .element: class="fragment fade-in" --> Avoid explicit <code>new</code>
* <!-- .element: class="fragment fade-in" --> Use <code>std::make_shared()</code> / <code>std::make_unique()</code>
* <!-- .element: class="fragment fade-in" --> Avoid copying <code>std::shared_ptr<></code> when this is not neccessary.
* <!-- .element: class="fragment fade-in" --> Use references instead of pointers (as argument to function)
* <!-- .element: class="fragment fade-in" --> Almost always use <code>unique_ptr</code>
* <!-- .element: class="fragment fade-in" --> Use <code>shared_ptr</code> <b>ONLY</b> when you need to share ownership of object.
___
## Rule of 0, Rule of 5
### Rule of 5 <!-- .element: class="fragment fade-in" -->
* <!-- .element: class="fragment fade-in" --> If you need to implement one of those functions:
* <!-- .element: class="fragment fade-in" --> destructor
* <!-- .element: class="fragment fade-in" --> copy constructor
* <!-- .element: class="fragment fade-in" --> copy assignment operator
* <!-- .element: class="fragment fade-in" --> move constructor
* <!-- .element: class="fragment fade-in" --> move assignment operator
* <!-- .element: class="fragment fade-in" --> It probably means that you should implement them all, because you have manual resources management.
### Rule of 0 <!-- .element: class="fragment fade-in" -->
* <!-- .element: class="fragment fade-in" --> If you use RAII wrappers on resources, you dont need to implement any of Rule of 5 functions.
___
## Avoid explicit `new`
* <!-- .element: class="fragment fade-in" --> Smart pointers eliminate the need to use <code>delete</code> explicitly
* <!-- .element: class="fragment fade-in" --> To be symmetrical, do not use <code>new</code> as well
* <!-- .element: class="fragment fade-in" --> Allocate using:
* <!-- .element: class="fragment fade-in" --> <code>std::make_unique()</code>
* <!-- .element: class="fragment fade-in" --> <code>std::make_shared()</code>
* <!-- .element: class="fragment fade-in" --> use <code>new</code> only when you need to create ptr with custom deleter
___
<!-- .slide: style="font-size: 0.8em" -->
### Use `std::make_shared()` / `std::make_unique()`
* <!-- .element: class="fragment fade-in" --> What is a problem here?
```cpp
struct MyData { int value; };
using Ptr = std::shared_ptr<MyData>;
void sink(Ptr oldData, Ptr newData);
void use(void) {
sink(Ptr{new MyData{41}}, Ptr{new MyData{42}});
}
```
<!-- .element: class="fragment fade-in" -->
* <!-- .element: class="fragment fade-in" --> Hint: this version is not problematic
```cpp
struct MyData { int value; };
using Ptr = std::shared_ptr<MyData>;
void sink(Ptr oldData, Ptr newData);
void use(void) {
Ptr oldData{new MyData{41}};
Ptr newData{new MyData{42}};
sink(std::move(oldData), std::move(newData));
}
```
<!-- .element: class="fragment fade-in" -->
___
### Allocation deconstructed
`auto p = new MyData(10);` means:
* <!-- .element: class="fragment fade-in" --> allocate <code>sizeof(MyData)</code> bytes
* <!-- .element: class="fragment fade-in" --> run <code>MyData</code> constructor
* <!-- .element: class="fragment fade-in" --> assign address of allocated memory to <code>p</code>
Order of evaluation of any part of any expression, including order of evaluation of function arguments is <a href="https://en.cppreference.com/w/cpp/language/eval_order" target="_top">**unspecified**</a>. The compiler can evaluate operands and other subexpressions in any order, and may choose another order when the same expression is evaluated again. There is no concept of left-to-right or right-to-left evaluation in C++. <b>This is not a problem since C++17</b> due to the changes in the evaluation order of function arguments. Specifically, each argument to a function is required to fully execute before evaluation of other arguments.
<!-- .element: class="fragment fade-in box" -->
___
<!-- .slide: style="font-size: 0.77em" -->
### Unspecified order of evaluation
* How about two such operations (before C++17)?
| first operation (A) | second operation (B) |
| :-------------------------------------------- | :-------------------------------------------- |
| (1) allocate `sizeof(MyData)` bytes | (1) allocate `sizeof(MyData)` bytes |
| (2) run `MyData` constructor | (2) run `MyData` constructor |
| (3) assign address of allocated memory to `p` | (3) assign address of allocated memory to `p` |
* <!-- .element: class="fragment fade-in" --> Unspecified order of evaluation means that order can be for example:
* A1, A2, B1, B2, A3, B3
* <!-- .element: class="fragment fade-in" --> What if B2 throws an exception?
___
### Use `std::make_shared()` / `std::make_unique()`
* <!-- .element: class="fragment fade-in" --> <code>std::make_shared()</code> / <code>std::make_unique()</code> resolves this problem
```cpp
struct MyData{ int value; };
using Ptr = std::shared_ptr<MyData>;
void sink(Ptr oldData, Ptr newData);
void use() {
sink(std::make_shared<MyData>(41), std::make_shared<MyData>(42));
}
```
<!-- .element: class="fragment fade-in" -->
* <!-- .element: class="fragment fade-in" --> Fixes previous bug
* <!-- .element: class="fragment fade-in" --> Does not repeat a constructed type
* <!-- .element: class="fragment fade-in" --> Does not use explicit <code>new</code>
* <!-- .element: class="fragment fade-in" --> Optimizes memory usage (only for <code>std::make_shared()</code>)
___
## Copying `std::shared_ptr<>`
```cpp
void foo(std::shared_ptr<MyData> p);
void bar(std::shared_ptr<MyData> p) {
foo(p);
}
```
* <!-- .element: class="fragment fade-in" --> requires counters incrementing / decrementing
* <!-- .element: class="fragment fade-in" --> atomics / locks are not free
* <!-- .element: class="fragment fade-in" --> will call destructors
##### Can be better?
<!-- .element: class="fragment fade-in" -->
___
## Copying `std::shared_ptr<>`
```cpp
void foo(const std::shared_ptr<MyData> & p);
void bar(const std::shared_ptr<MyData> & p) {
foo(p);
}
```
* <!-- .element: class="fragment fade-in" --> as fast as pointer passing
* <!-- .element: class="fragment fade-in" --> no extra operations
* <!-- .element: class="fragment fade-in" --> not safe in multithreaded applications
___
### Use references instead of pointers
* <!-- .element: class="fragment fade-in" --> What is the difference between a pointer and a reference?
* <!-- .element: class="fragment fade-in" --> reference cannot be empty
* <!-- .element: class="fragment fade-in" --> reference, once assigned cannot point to anything else
* <!-- .element: class="fragment fade-in" --> Priorities of usage (if possible):
* <!-- .element: class="fragment fade-in" --> <code>(const) T&</code>
* <!-- .element: class="fragment fade-in" --> <code>std::unique_ptr&ltT&gt</code>
* <!-- .element: class="fragment fade-in" --> <code>std::shared_ptr&ltT&gt</code>
* <!-- .element: class="fragment fade-in" --> <code>T*</code>
___
## Exercise: List
Take a look at `List.cpp` file, where simple (and buggy) single-linked list is implemented.
* `pushFront` method adds a new `Node` at the begining of the list.
* `findByValue` method iterates over the list and returns the first Node with matching `value` or `nullptr`.
1. <!-- .element: class="fragment fade-in" --> Compile and run List application
2. <!-- .element: class="fragment fade-in" --> Fix memory leaks without introducing smart pointers
3. <!-- .element: class="fragment fade-in" --> Fix memory leaks with smart pointers. What kind of pointers needs to be applied and why?
4. <!-- .element: class="fragment fade-in" --> Add function to add a node at the end of the list (try to do this with time complexity O(1))
5. <!-- .element: class="fragment fade-in" --> Add function to delete node with provided value.
<!-- .slide: style="font-size: 0.8em" -->

View file

@ -0,0 +1,181 @@
<!-- .slide: data-background="#ccc" -->
# Efficiency
___
## Raw pointer
```cpp
#include <memory>
#include <vector>
struct Data {
char tab_[42];
};
int main(void) {
constexpr unsigned size = 10u * 1000u * 1000u;
std::vector<Data *> v;
v.reserve(size);
for (unsigned i = 0; i < size; ++i) {
auto p = new Data;
v.push_back(std::move(p));
}
for (auto p: v)
delete p;
}
```
___
## Unique pointer
```cpp
#include <memory>
#include <vector>
struct Data {
char tab_[42];
};
int main(void) {
constexpr unsigned size = 10u * 1000u * 1000u;
std::vector<std::unique_ptr<Data>> v;
v.reserve(size);
for (unsigned i = 0; i < size; ++i) {
std::unique_ptr<Data> p{new Data};
v.push_back(std::move(p));
}
}
```
___
## Shared pointer
```cpp
#include <memory>
#include <vector>
struct Data {
char tab_[42];
};
int main(void) {
constexpr unsigned size = 10u * 1000u * 1000u;
std::vector<std::shared_ptr<Data>> v;
v.reserve(size);
for (unsigned i = 0; i < size; ++i) {
std::shared_ptr<Data> p{new Data};
v.push_back(std::move(p));
}
}
```
___
## Shared pointer `make_shared`
```cpp
#include <memory>
#include <vector>
struct Data {
char tab_[42];
};
int main(void) {
constexpr unsigned size = 10u * 1000u * 1000u;
std::vector<std::shared_ptr<Data>> v;
v.reserve(size);
for (unsigned i = 0; i < size; ++i) {
auto p = std::make_shared<Data>();
v.push_back(std::move(p));
}
}
```
___
## Weak pointer
```cpp
#include <memory>
#include <vector>
struct Data {
char tab_[42];
};
int main(void) {
constexpr unsigned size = 10u * 1000u * 1000u;
std::vector<std::shared_ptr<Data>> vs;
std::vector<std::weak_ptr<Data>> vw;
vs.reserve(size);
vw.reserve(size);
for (unsigned i = 0; i < size; ++i) {
std::shared_ptr<Data> p{new Data};
std::weak_ptr<Data> w{p};
vs.push_back(std::move(p));
vw.push_back(std::move(w));
}
}
```
___
## Measurements
* <!-- .element: class="fragment fade-in" --> gcc-4.8.2
* <!-- .element: class="fragment fade-in" --> compilation with <code>std=c++11 O3 DNDEBUG</code>
* <!-- .element: class="fragment fade-in" --> measuring with:
* <!-- .element: class="fragment fade-in" --> time (real)
* <!-- .element: class="fragment fade-in" --> htop (mem)
* <!-- .element: class="fragment fade-in" --> valgrind (allocations count)
___
## Results
| test name | time [s] | allocations | memory [MB] |
|:--------------:|:--------:|:-----------:|:-----------:|
| raw pointer <!-- .element: class="fragment fade-in" --> | 0.54 <!-- .element: class="fragment fade-in" --> | 10 000 001 <!-- .element: class="fragment fade-in" --> | 686 <!-- .element: class="fragment fade-in" --> |
| unique pointer <!-- .element: class="fragment fade-in" --> | 0.56 <!-- .element: class="fragment fade-in" --> | 10 000 001 <!-- .element: class="fragment fade-in" --> | 686 <!-- .element: class="fragment fade-in" --> |
| shared pointer <!-- .element: class="fragment fade-in" --> | 1.00 <!-- .element: class="fragment fade-in" --> | 20 000 001 <!-- .element: class="fragment fade-in" --> | 1072 <!-- .element: class="fragment fade-in" --> |
| make shared <!-- .element: class="fragment fade-in" --> | 0.76 <!-- .element: class="fragment fade-in" --> | 10 000 001 <!-- .element: class="fragment fade-in" --> | 914 <!-- .element: class="fragment fade-in" --> |
| weak pointer <!-- .element: class="fragment fade-in" --> | 1.28 <!-- .element: class="fragment fade-in" --> | 20 000 002 <!-- .element: class="fragment fade-in" --> | 1222 <!-- .element: class="fragment fade-in" --> |
___
## Conclusions
* <!-- .element: class="fragment fade-in" --> RAII
* <!-- .element: class="fragment fade-in" --> acquire resource in constructor
* <!-- .element: class="fragment fade-in" --> release resource in destructor
* <!-- .element: class="fragment fade-in" --> Rule of 5, Rule of 0
* <!-- .element: class="fragment fade-in" --> Smart pointers:
* <!-- .element: class="fragment fade-in" --> <code>std::unique_ptr</code> primary choice, no overhead, can convert to <code>std::shared_ptr</code>
* <!-- .element: class="fragment fade-in" --> <code>std::shared_ptr</code> introduces memory and runtime overhead
* <!-- .element: class="fragment fade-in" --> <code>std::weak_ptr</code> breaking cycles, can convert to/from <code>std::shared_ptr</code>
* <!-- .element: class="fragment fade-in" --> Create smart pointers with <code>std::make_shared()</code> and <code>std::make_unique()</code>
* <!-- .element: class="fragment fade-in" --> Raw pointer should mean „access only” (no ownership)
* <!-- .element: class="fragment fade-in" --> Use reference instead of pointers if possible
___
## Post-work
* <!-- .element: class="fragment fade-in" --> Transform the list from <code>List.cpp</code> into double-linked list. You should implement:
* <!-- .element: class="fragment fade-in" --> inserting Nodes at the beginning of the list
* <!-- .element: class="fragment fade-in" --> searching elements in reverse
* <!-- .element: class="fragment fade-in" --> Apply proper smart pointers for the reverse direction.
* <!-- .element: class="fragment fade-in" --> Implement your own <code>unique_ptr</code>. Requirements:
* <!-- .element: class="fragment fade-in" --> Templatized (should hold a pointer to a template type)
* <!-- .element: class="fragment fade-in" --> RAII (acquire in constructor, release in destructor)
* <!-- .element: class="fragment fade-in" --> Copying not allowed
* <!-- .element: class="fragment fade-in" --> Moving allowed
* <!-- .element: class="fragment fade-in" --> Member functions: <code>operator*()</code>, <code>operator->()</code>, <code>get()</code>, <code>release()</code>, <code>reset()</code>
* <!-- .element: class="fragment fade-in" --> Read one of these articles on move semantics:
* <!-- .element: class="fragment fade-in" --> <a href="https://infotraining.bitbucket.io/cpp-11/move.html">Semantyka przenoszenia</a> (in Polish)
* <!-- .element: class="fragment fade-in" --> <a href="https://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html">Move semantics and rvalue references in C++11</a> (in English)

View file

@ -0,0 +1,122 @@
<!-- .slide: data-background="#ccc" -->
# Implementation details
___
### Implementation details `std::unique_ptr<>`
* <!-- .element: class="fragment fade-in" --> Just a holding wrapper
* <!-- .element: class="fragment fade-in" --> Holds an object pointer
* <!-- .element: class="fragment fade-in" --> Constructor copies a pointer
* <!-- .element: class="fragment fade-in" --> Call proper delete in destructor
* <!-- .element: class="fragment fade-in" --> No copying
* <!-- .element: class="fragment fade-in" --> Moving means:
* <!-- .element: class="fragment fade-in" --> Copying original pointer to a new object
* <!-- .element: class="fragment fade-in" --> Setting source pointer to <code>nullptr</code>
___
### Implementation details `std::shared_ptr<>`
<img data-src="img/sharedptr2inverted.png" alt="sharedptr2" class="plain fragment fade-in">
* <!-- .element: class="fragment fade-in" --> Holds an object pointer
* <!-- .element: class="fragment fade-in" --> Holds 2 reference counters:
* <!-- .element: class="fragment fade-in" --> shared pointers count
* <!-- .element: class="fragment fade-in" --> weak pointers count
* <!-- .element: class="fragment fade-in" --> Destructor:
* <!-- .element: class="fragment fade-in" --> decrements <code>shared-refs</code>
* <!-- .element: class="fragment fade-in" --> deletes user data when <code>shared-refs == 0</code>
* <!-- .element: class="fragment fade-in" --> deletes reference counters when <code>shared-refs == 0</code> and <code>weak-refs == 0</code>
* <!-- .element: class="fragment fade-in" --> Extra space for a deleter
___
### Implementation details `std::shared_ptr<>`
* <!-- .element: class="fragment fade-in" --> Copying means:
* <!-- .element: class="fragment fade-in" --> Copying pointers to the target
* <!-- .element: class="fragment fade-in" --> Incrementing <code>shared-refs</code>
<img data-src="img/sharedptr3inverted.png" alt="sharedptr3" class="plain fragment fade-in">
* <!-- .element: class="fragment fade-in" --> Moving means:
* <!-- .element: class="fragment fade-in" --> Copying pointers to the target
* <!-- .element: class="fragment fade-in" --> Setting source pointers to <code>nullptr</code>
<img data-src="img/sharedptr4inverted.png" alt="sharedptr4" class="plain fragment fade-in">
___
### Implementation details `std::weak_ptr<>`
* <!-- .element: class="fragment fade-in" --> Holds an object pointer
* <!-- .element: class="fragment fade-in" --> Holds 2 reference counters:
* <!-- .element: class="fragment fade-in" --> shared pointers count
* <!-- .element: class="fragment fade-in" --> weak pointers count
* <!-- .element: class="fragment fade-in" --> Destructor:
* <!-- .element: class="fragment fade-in" --> decrements <code>weak-refs</code>
* <!-- .element: class="fragment fade-in" --> deletes reference counters when <code>shared-refs == 0</code> and <code>weak-refs == 0</code>
<img data-src="img/sharedptr5inverted.png" alt="sharedptr5" class="plain fragment fade-in">
___
### Implementation details `std::weak_ptr<>`
* <!-- .element: class="fragment fade-in" --> Copying means:
* <!-- .element: class="fragment fade-in" --> Copying pointers to the target
* <!-- .element: class="fragment fade-in" --> Incrementing <code>weak-refs</code>
<img data-src="img/sharedptr6inverted.png" alt="sharedptr6" class="plain fragment fade-in">
* <!-- .element: class="fragment fade-in" --> Moving means:
* <!-- .element: class="fragment fade-in" --> Copying pointers to the target
* <!-- .element: class="fragment fade-in" --> Setting source pointers to <code>nullptr</code>
<img data-src="img/sharedptr7inverted.png" alt="sharedptr7" class="plain fragment fade-in">
___
### `std::weak_ptr<>` + `std::shared_ptr<>`
* <!-- .element: class="fragment fade-in" --> Having a shared pointer and a weak pointer
<img data-src="img/sharedptr8inverted.png" alt="sharedptr8" class="plain fragment fade-in">
* <!-- .element: class="fragment fade-in" --> After removing the shared pointer
<img data-src="img/sharedptr9inverted.png" alt="sharedptr9" class="plain fragment fade-in">
___
## Making a `std::shared_ptr<>`
<!-- .slide: style="font-size: 0.75em" -->
<div class="multicolumn">
<div class="col">
<!-- .slide: style="font-size: 0.85em" -->
* <!-- .element: class="fragment fade-in" --> <code>std::shared_ptr&ltData&gt p{new Data};</code>
* <!-- .element: class="fragment fade-in" --> Perform two allocations: one for control block and second for data
* <!-- .element: class="fragment fade-in" --> Before C++17 can make a problem with ordering of operations
* <!-- .element: class="fragment fade-in" --> When all <code>shared_ptr</code> will be deleted but there is some <code>weak_ptr</code> allocated memory for data <b>can be freed</b>.
<img data-src="img/sharedptr10inverted.png" alt="sharedptr10" class="plain fragment fade-in" height="150px">
</div>
<div class = "col">
<!-- .slide: style="font-size: 0.85em" -->
* <!-- .element: class="fragment fade-in" --> <code>auto p = std::make_shared&ltData&gt();</code>
* <!-- .element: class="fragment fade-in" --> Less memory (most likely)
* <!-- .element: class="fragment fade-in" --> Only one allocation
* <!-- .element: class="fragment fade-in" --> Cache-friendly
* <!-- .element: class="fragment fade-in" --> When all <code>shared_ptr</code> will be deleted but there is some <code>weak_ptr</code> allocated memory for data <b>cannot be freed</b>
<img data-src="img/sharedptr11inverted.png" alt="sharedptr11" class="plain fragment fade-in" height="150px">
</div>
</div>

View file

@ -0,0 +1,189 @@
<!-- .slide: data-background="#ccc" -->
# `std::shared_ptr<>`
___
### `std::shared_ptr<>`
* <!-- .element: class="fragment fade-in" --> one object == multiple owners
* <!-- .element: class="fragment fade-in" --> last referrer destroys the object
* <!-- .element: class="fragment fade-in" --> copying allowed
* <!-- .element: class="fragment fade-in" --> moving allowed
* <!-- .element: class="fragment fade-in" --> can use custom deleter
* <!-- .element: class="fragment fade-in" --> can use custom allocator
* <!-- .element: class="fragment fade-in" --> has a control block == impact on size of pointer end efficiency
<img data-src="img/sharedptr1inverted.png" alt="shared pointers" class="plain fragment fade-in">
___
<!-- .slide: style="font-size: 0.85em" -->
### `std::shared_ptr<>` usage (1)
* Copying and moving is allowed
<div class="multicolumn">
<div class="col">
```cpp
std::shared_ptr<MyData> source();
void sink(std::shared_ptr<MyData> ptr);
void simpleUsage() {
source();
sink(source());
auto ptr = source();
sink(ptr);
sink(std::move(ptr));
auto p1 = source();
auto p2 = p1;
p2 = std::move(p1);
p1 = p2;
p1 = std::move(p2);
}
```
</div>
<div class="col">
```cpp
std::shared_ptr<MyData> source();
void sink(std::shared_ptr<MyData> ptr);
void collections() {
std::vector<std::shared_ptr<MyData>> v;
v.push_back(source());
auto tmp = source();
v.push_back(tmp);
v.push_back(std::move(tmp));
sink(v[0]);
sink(std::move(v[0]));
}
```
</div>
</div>
___
<!-- .slide: style="font-size: 0.85em" -->
### `std::shared_ptr<>` usage (2)
```cpp
#include <memory>
#include <map>
#include <string>
class Gadget {};
std::map<std::string, std::shared_ptr<Gadget>> gadgets;
void foo() {
std::shared_ptr<Gadget> p1{new Gadget()}; // reference counter = 1
{
auto p2 = p1; // copy (reference counter == 2)
gadgets.insert(make_pair("mp3", p2)); // copy (reference counter == 3)
p2->use();
} // destruction of p2, reference counter = 2
} // destruction of p1, reference counter = 1
int main() {
foo();
gadgets.clear(); // reference counter = 0 - gadget is removed
}
```
___
### Custom deleter
* <!-- .element: class="fragment fade-in" --> Don't change a type of <code>shared_ptr</code> because data is stored in control block
* <!-- .element: class="fragment fade-in" --> Don't change a size of <code>shared_ptr</code> because data is stored in control block
* <!-- .element: class="fragment fade-in" --> You can have a collection of <code>shared_ptr</code> which has different deleter
<div class="multicolumn">
<div class="col">
```C++
class Foo {};
void deleter1(Foo* const foo) {
std::cout << "Deleter1\n";
delete foo;
}
int main() {
std::vector<std::shared_ptr<Foo>> vec;
std::shared_ptr<Foo> ptr1(new Foo(), deleter1);
vec.push_back(std::move(ptr1));
auto deleter2 = [](Foo* const foo) {
std::cout << "Deleter2\n";
delete foo;
};
vec.emplace_back(new Foo(), deleter2);
}
```
<!-- .element: class="fragment fade-in" -->
</div>
<div class="col">
```Bash
Deleter1
Deleter2
```
<!-- .element: class="fragment fade-in" -->
</div>
<!-- .slide: style="font-size: 0.8em" -->
___
### Problem with shared_ptr
Let's look at a short story:
* <!-- .element: class="fragment fade-in" --> Programmer1 : Why do you pass shared_ptr by copy? Passing by copy increment counter (slower then unique or raw ptr)
* <!-- .element: class="fragment fade-in" --> Programmer2: Ok, so I will pass it by const reference instead! And avoid unnecessary incrementation of the control block.
* <!-- .element: class="fragment fade-in" --> Programmer1: So if you don't need to copy it (don't need to have 2 owners) why don't use unique_ptr?
* <!-- .element: class="fragment fade-in" --> <b>Reassume</b>: shared_ptr should be use <b>only when given resource need to have few owners</b> (very rare situation). In other case use always unique_ptr!
___
### `std::shared_ptr<>` cyclic dependencies
* What happens here?
<div class="multicolumn" style="position: relative">
<div class="col" style="width: 65%; flex: none">
```cpp
#include <memory>
struct Node {
std::shared_ptr<Node> child;
std::shared_ptr<Node> parent;
};
int main () {
auto root = std::shared_ptr<Node>(new Node);
auto child = std::shared_ptr<Node>(new Node);
root->child = child;
child->parent = root;
}
```
</div>
<div class="col fragment fade-in">
Memory leak!
<img data-src="img/kot.jpg" alt="kot" class="plain" style="height: 50%">
</div>

View file

@ -0,0 +1,21 @@
<!-- .slide: data-background="#ccc" -->
# Smart pointers
___
## Smart pointers
* <!-- .element: class="fragment fade-in" --> A smart pointer manages a pointer to a heap allocated object
* <!-- .element: class="fragment fade-in" --> Deletes the pointed-to object at the right time
* <!-- .element: class="fragment fade-in" --> <code>operator->()</code> calls managed object methods
* <!-- .element: class="fragment fade-in" --> <code>operator.()</code> calls smart pointer methods
* <!-- .element: class="fragment fade-in" --> smart pointer to a base class can hold a pointer to a derived class
* <!-- .element: class="fragment fade-in" --> STL smart pointers:
* <!-- .element: class="fragment fade-in" --> <code>std::unique_ptr<></code>
* <!-- .element: class="fragment fade-in" --> <code>std::shared_ptr<></code>
* <!-- .element: class="fragment fade-in" --> <code>std::weak_ptr<></code>
* <!-- .element: class="fragment fade-in" --> <code>std::auto_ptr<></code> - removed in C++17

View file

@ -0,0 +1,18 @@
<!-- .slide: data-background="#ccc" -->
# Smart pointers - summary
* <!-- .element: class="fragment fade-in" --> <code>#include &ltmemory&gt</code>
* <!-- .element: class="fragment fade-in" --> <code>std::unique_ptr<></code> for exclusive ownership
* <!-- .element: class="fragment fade-in" --> <code>std::shared_ptr<></code> for shared ownership
* <!-- .element: class="fragment fade-in" --> <code>std::weak_ptr<></code> for observation and breaking cycles
___
## Exercise: ResourceFactory
1. <!-- .element: class="fragment fade-in" --> Compile and run ResourceFactory application
2. <!-- .element: class="fragment fade-in" --> Put comments in places where you can spot some problems
3. <!-- .element: class="fragment fade-in" --> How to remove elements from the collection (<code>vector&ltResource*&gt</code> resources)?
4. <!-- .element: class="fragment fade-in" --> Check memory leaks
5. <!-- .element: class="fragment fade-in" --> Fix problems

View file

@ -0,0 +1,434 @@
<!-- .slide: data-background="#ccc" -->
# `std::unique_ptr<>`
___
## `std::unique_ptr<>`
<div>
* <!-- .element: class="fragment fade-in" --> one object == one owner
* <!-- .element: class="fragment fade-in" --> destructor destroys the object
* <!-- .element: class="fragment fade-in" --> copying not allowed
* <!-- .element: class="fragment fade-in" --> moving allowed
* <!-- .element: class="fragment fade-in" --> can use custom deleter
* <!-- .element: class="fragment fade-in" --> <a href="https://quick-bench.com/q/kZs8qerce1or9_0R0QNezh_hVM4" target="_top">0 cost class -> no impact on efficiency</a>
</div>
<img data-src="img/uniqueptrinverted.png" alt="unique pointers" class="plain fragment fade-in">
___
### `std::unique_ptr<>` usage
* Old style approach vs modern approach
<div class="multicolumn">
<div class="col">
```cpp
#include <iostream> // old-style approach
struct Msg {
int getValue() { return 42; }
};
Msg* createMsg() {
return new Msg{};
}
int main() {
auto msg = createMsg();
std::cout << msg->getValue();
delete msg;
}
```
<!-- .element: class="fragment fade-in" -->
</div>
<div class="col">
```cpp
#include <memory> // modern approach
#include <iostream>
struct Msg {
int getValue() { return 42; }
};
std::unique_ptr<Msg> createMsg() {
return std::make_unique<Msg>();
}
int main() {
// unique ownership
auto msg = createMsg();
std::cout << msg->getValue();
}
```
<!-- .element: class="fragment fade-in" -->
</div>
___
### `std::unique_ptr<>` usage
* <!-- .element: class="fragment fade-in" --> Copying is not allowed
* <!-- .element: class="fragment fade-in" --> Moving is allowed
<div class="multicolumn">
<div class="col">
```cpp
std::unique_ptr<MyData> source(void);
void sink(std::unique_ptr<MyData> ptr);
void simpleUsage() {
source();
sink(source());
auto ptr = source();
// sink(ptr); // compilation error
sink(std::move(ptr));
auto p1 = source();
// auto p2 = p1; // compilation error
auto p2 = std::move(p1);
// p1 = p2; // compilation error
p1 = std::move(p2);
}
```
<!-- .element: class="fragment fade-in" -->
</div>
<div class="col">
```cpp
std::unique_ptr<MyData> source(void);
void sink(std::unique_ptr<MyData> ptr);
void collections() {
std::vector<std::unique_ptr<MyData>> v;
v.push_back(source());
auto tmp = source();
// v.push_back(tmp); // compilation error
v.push_back(std::move(tmp));
// sink(v[0]); // compilation error
sink(std::move(v[0]));
}
```
<!-- .element: class="fragment fade-in" -->
</div>
___
#### `std::unique_ptr<>` problem with containers
<div class="col">
<!-- .element: class="fragment fade-in" --> What is wrong with this part of code?
<!-- .element: class="fragment fade-in" -->
```cpp
std::unique_ptr<MyData> source(void);
void sink(std::unique_ptr<MyData> ptr);
void collections() {
std::vector<std::unique_ptr<MyData>> v;
v.push_back(source());
auto tmp = source();
v.push_back(std::move(tmp));
sink(std::move(v[0]));
std::cout << *(v[0]) << '\n';
}
```
</div>
___
#### `std::unique_ptr<>` cooperation with raw pointers
```cpp
#include <memory>
void legacyInterface(int*) {}
void deleteResource(int* p) { delete p; }
void referenceInterface(int&) {}
int main() {
auto ptr = std::make_unique<int>(5);
legacyInterface(ptr.get());
deleteResource(ptr.release());
ptr.reset(new int{10});
referenceInterface(*ptr);
ptr.reset(); // ptr is a nullptr
return 0;
}
```
* <!-- .element: class="fragment fade-in" --> <code>get()</code> returns a raw pointer without releasing the ownership
* <!-- .element: class="fragment fade-in" --> <code>release()</code> returns a raw pointer and release the ownership
* <!-- .element: class="fragment fade-in" --> <code>reset()</code> replaces the manager object
* <!-- .element: class="fragment fade-in" --> <code>operator*()</code> dereferences pointer to the managed object
___
### `std::make_unique()`
```cpp
#include <memory>
struct Msg {
Msg(int i) : value(i) {}
int value;
};
int main() {
auto ptr1 = std::unique_ptr<Msg>(new Msg{5});
auto ptr2 = std::make_unique<Msg>(5); // equivalent to above
return 0;
}
```
`std::make_unique()` is a factory function that produce `unique_ptrs`
<!-- .element: class="fragment fade-in" -->
* <!-- .element: class="fragment fade-in" --> added in C++14 for symmetrical operations on unique and shared pointers
* <!-- .element: class="fragment fade-in" --> avoids bare <code>new</code> expression
___
### `std::unique_ptr<T[]>`
```cpp
struct MyData {};
void processPointer(MyData* md) {}
void processElement(MyData md) {}
using Array = std::unique_ptr<MyData[]>;
void use(void)
{
Array tab{new MyData[42]};
processPointer(tab.get());
processElement(tab[13]);
}
```
* <!-- .element: class="fragment fade-in" --> During destruction
* <!-- .element: class="fragment fade-in" --> <code>std::unique_ptr&ltT&gt</code> calls <code>delete</code>
* <!-- .element: class="fragment fade-in" --> <code>std::unique_ptr&ltT[]&gt</code> calls <code>delete[]</code>
* <!-- .element: class="fragment fade-in" --> <code>std::unique_ptr&ltT[]&gt</code> has additional <code>operator[]</code> for accessing array element
* <!-- .element: class="fragment fade-in" --> Usually <code>std::vector&ltT&gt</code> is a better choice
___
## Exercise: Resource
1. <!-- .element: class="fragment fade-in" --> Compile and run Resource application
2. <!-- .element: class="fragment fade-in" --> Check memory leaks under valgrind
3. <!-- .element: class="fragment fade-in" --> Fix memory leaks with a proper usage of <code>delete</code> operator
4. <!-- .element: class="fragment fade-in" --> Refactor the solution to use <code>std::unique_ptr<></code>
5. <!-- .element: class="fragment fade-in" --> Use <code>std::make_unique()</code>
___
## Exercise: Converter
1. <!-- .element: class="fragment fade-in" --> Compile and run Converter application and check memory leaks under valgrind
2. <!-- .element: class="fragment fade-in" --> Fix code using std::unique_ptr and std::make_unique
3. <!-- .element: class="fragment fade-in" --> Find other issues and fix them (use good practise etc...)
___
## Why virtual D'tor is so important (1)?
```C++
class Resource {
public:
explicit Resource(const std::string& str): str_(str) {}
const std::string& str() const {
return str_;
}
private:
std::string str_;
};
class Converter {
public:
Converter() {
std::cout << "C'tor converter\n";
}
virtual ~Converter() {
std::cout << "D'tor converter\n";
}
virtual void Convert(const std::unique_ptr<Resource>& resource) const = 0;
};
class CurlyBracketConverter : public Converter {
public:
CurlyBracketConverter() {
std::cout << "C'tor CurlyBracketConverter\n";
}
~CurlyBracketConverter() override {
std::cout << "D'tor CurlyBracketConverter\n";
}
void Convert(const std::unique_ptr<Resource>& resource) const override {
std::cout << "{" << resource->str() << "}\n";
}
};
class SquareBracketConverter : public Converter {
public:
SquareBracketConverter() {
std::cout << "C'tor SquareBracketConverter\n";
}
~SquareBracketConverter() override {
std::cout << "D'tor SquareBracketConverter\n";
}
virtual void Convert(const std::unique_ptr<Resource>& resource) const override{
std::cout << "[" << resource->str() << "]\n";
}
};
class Printer {
public:
explicit Printer(std::unique_ptr<Converter> converter): converter_(std::move(converter)) {}
void Print(const std::unique_ptr<Resource>& resource) const {
converter_->Convert(resource);
}
private:
std::unique_ptr<Converter> converter_;
};
int main() {
auto resource = std::make_unique<Resource>("Ala has a cat");
Printer printer(std::make_unique<SquareBracketConverter>());
Printer printer2(std::make_unique<CurlyBracketConverter>());
return 0;
}
```
<!-- .element: style="font-size: 0.8rem" -->
___
## Why virtual D'tor is so important (2)?
```C++
C'tor converter
C'tor SquareBracketConverter
C'tor converter
C'tor CurlyBracketConverter
D'tor converter
D'tor converter
```
<!-- .element: style="font-size: 1.2rem" -->
<!-- .element: class="fragment fade-in" -->
Try to add virtual to your D'tor and check result
<!-- .element: class="fragment fade-in" -->
```C++
C'tor converter
C'tor SquareBracketConverter
C'tor converter
C'tor CurlyBracketConverter
D'tor CurlyBracketConverter
D'tor converter
D'tor SquareBracketConverter
D'tor converter
```
<!-- .element: class="fragment fade-in" -->
___
## Custom Deleter
* <!-- .element: class="fragment fade-in" --> When there is a special way to delete object
* <!-- .element: class="fragment fade-in" --> Type of unique_ptr change!
<div class="multicolumn">
<div class="col">
```C++
class Foo {
public:
Foo() {
std::cout << "Foo C'tor\n";
}
void print() const {
std::cout << "Foo!\n";
}
private:
// For some reason, we allow only this function to delete object
friend void deleteMe(Foo* const foo);
~Foo() {
std::cout << "Foo D'tor\n";
}
};
void deleteMe(Foo* const foo) {
std::cout << "Delete object Foo!\n";
delete foo;
}
int main() {
// Can't use make unique, need to use unique_ptr C'tor
// unique_ptr(pointer __p, const deleter_type& __d) noexcept
std::unique_ptr<Foo, void(*)(Foo* const)> ptr(new Foo, deleteMe);
ptr->print();
return 0;
}
```
<!-- .element: style="font-size: 0.8rem" -->
<!-- .element: class="fragment fade-in" -->
</div>
<div class="col">
<!-- .element: class="fragment fade-in" --> Output
```C++
Foo C'tor
Foo!
Delete object Foo!
Foo D'tor
```
<!-- .element: class="fragment fade-in" -->
</div>

Some files were not shown because too many files have changed in this diff Show more