More in Modern C++ John van Krieken tussen accolades B.V. {tussen}
Smart pointers Naked * Ownership? {tussen}
Pointers in classes struct X { X(): a(new A), b(new B) {} X(const X& src) : a(new A (*src.a)), b(new B (*src.b)) {} X(X&& src) : a(src.a), b(src.b) { src.a = src.b = nullptr; } X& operator= (const X&) = delete; X& operator= (X&&) = delete; ~X() { delete a; delete b: } A *a; B *b; }; Everyone knows how to do this, right? {tussen}
unique_ptr unique_ptr<T> unique_ptr<T[]> unique_ptr<X> clone() const { return unique_ptr<X>(new X(*this)); } auto clone2() const // (14) { return make_unique<X>(*this); } {tussen}
Smart pointers in classes struct X { X(): a(new A), b(new B) {} X(const X& src) : a(new A (*src.a)), b(new B (*src.b)) {} X(X&& src) : a(std::move(src.a)), b(std::move(src.b)){} X& operator= (const X&) = delete; X& operator= (X&&) = default; ~X() = default; std::unique_ptr<A> a; std::unique_ptr<B> b; }; X(X&& src) = default; // unless you have non-movables Need I say more? {tussen}
Moving pointers around class X { X& operator=(const X&) = delete; protected: X(const X&) = default; public: X() = default; X* clone() const { return new X(*this); } clone obviously }; gives ownership X x1; auto x2 = x1.clone(); //X x3(x1); // forbidden X x4; //x4 = x1; // forbidden x1.clone(); memory {tussen} leak
Moving ownership class X { public: unique_ptr<X> clone() const { return unique_ptr<X>(new X(*this)); } [[nodiscard]] auto clone2() const { return make_unique<X>(*this); } } class Y { public: Y() : ptr(nullptr) {} void set(unique_ptr<X>&& p) { ptr = std::move(p); } private: unique_ptr<X> ptr; auto x3 = x1.clone2(); }; Y y1; y1.set(std::move(x3)); warning destructor called y1.set(x1.clone()); [[nodiscard]] (17) no leak x1.clone(); x1.clone2(); {tussen}
Shared pointers shared_ptr<T> shared_ptr<T[]> // (17) shared_ptr<T> s = make_unique<T[]>(new T[n]) // (14) shared_ptr<T[]> s = make_unique<T[]>(new T[n]) // (17) incompatible! (but logical) {tussen}
Interoperability start here unique_ptr<T> release() c’tor reset() c’tor T* shared_ptr<T> observer<T> replacement for naked *(20) {tussen}
auto_ptr Removed from C++17 including the constructors for unique_ptr and shared_ptr that “steal” ownership from it. Chapter closed! {tussen}
𝛍 -functions {tussen}
syntaxis of 𝛍 -functions Parameters (optional, but) auto (14) body defaults (14) [] ()-> type {} Captures & : reference = : all by value returns (optional) local=var+4 : by value (14) defaults to type of single return this : object multiple returns allowed (14) *this : object copy (17) {tussen}
return type deduction Return type of lambda is either supplied with -> type or deduced from the single return in the body. C++14 relaxes this, so you can have multiple return -statements as long as they have the same type . auto mr = [](int a) { auto g_mr(int a) /* ->bool */ { if(a > 7) if(a > 7) return true; return true; else else return false; return false; }; }; static_assert(std::is_same<decltype(mr(9)), bool>::value, "multiple return"); static_assert(std::is_same<decltype(g_mr(9)), bool>::value, "function multiple return"); {tussen}
Mutable & constexpr auto y = 77; C++17 auto mut_l = [y] () mutable { y+=4; cout << y << endl; }; 81 mut_l(); 85 mut_l(); 77 cout << y << endl; auto cf_t = [](auto a, auto b) constexpr {return a+b;}; static_assert(cf_t(3,4) == 7, "generic lambda”); auto cf = [](int a, int b) constexpr noexcept(true) -> int {return a+b;}; static_assert(cf(3,4) == 7, "constexpr lambda"); C++14 [[deprecated(“Yup”)]] auto cf_d = [](int a, int b) constexpr -> int {return a+b;}; static_assert(cf_d(3,4) == 7, "deprecated lambda"); {tussen}
Initialisers and defaults auto with default value doesn’t work (for me)? auto x = 5; auto l = [mine=x+4](auto a, string b="Hallo"s) { cout << a << ' ' << b << ' ' << mine << endl; }; l(3); 3 Hallo 9 l(3.4, "seven"); 3.4 seven 9 {tussen}
Templated lambdas (C++20) auto templated_lambda = []<typename T>(T, T, auto){}; templated_lambda(3, 4, "Hello"s); // templated_lambda(3, 4.5, "Hello"s); wrong: 3 and 4.5 are of different types {tussen}
Meta programming {tussen}
Meta functions f or meta-functions with value, that value is wrapped in integral_constant<int, 7> . meta_fct<A> for predicates: is_… meta_fct<A>::type true_type, integral_constant<bool, true> false_type, integral_constant<bool, false> mate_fct<A>::value template <typename T> typename using f_t<T> = typename f<T>::type; // (14) is a nuisance template <typename T> using f_v = f<T>::value; // (17) more orthogonal {tussen}
Type computations // think template <typename T> … T t; typename std::add_pointer<T>::type t_ptr = &t; std::add_pointer_t<T> t_ptr2 = &t; static_assert(std::is_same<decltype(t_ptr), T*>::value, ""); static_assert(std::is_same_v<decltype(t_ptr2), T*>, ""); {tussen}
Conditionals template <typename T> struct add_pointer_if { using type = std::conditional_t<std::is_pointer_v<T>, T, T*>; }; template <typename T> using add_pointer_if_t = typename add_pointer_if<T>::type; static_assert(std::is_same<add_pointer_if_t<int>, int*>::value, "int -> int*"); static_assert(std::is_same_v<add_pointer_if<int*>::type, int*>, "int* == int*"); {tussen}
SFINA "Substitution Failure Is Not An Error" template<typename T, typename …Types> typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type make_unique(Types&& …args){ return std::unique_ptr<T> (new T(std::forwad<Type>(args)…)); } make_unique<T>(x, y,…); template <typename T> typename std::enable_if<std::is_array<T>::value && std::extend<T>::value == 0, std::unique_ptr<T>>::type make_unique(size_t size){ using Elem = typename std::remove_extend<T>::type; return std::unique_ptr<T[]> (new Elem[size]); make_unique<T[]>(7); } template<typename T, typename …Types> typename std::enable_if<std::extent<T>::value != 0, std::unique_ptr<T>>::type make_unique(Types&& …args) = delete; {tussen} make_unique<T[7]>();
boost.hana #include <boost/hana.hpp> namespace hana = boost::hana; struct Bird { std::string name; }; struct Fish { std::string name; }; struct Cat { std::string name; }; auto animals = hana::make_tuple(Bird{"Tweety"}, Fish{"Wanda"}, Cat{"Loki"}); auto anders = hana::reverse(animals); static_assert(std::is_same_v< decltype(anders) , hana::tuple<Cat, Fish, Bird> >, ""); {tussen}
Hana types are objects Template variable (14) auto four = hana::int_c<4>; using namespace hana::literals; static_assert(four == 4_c, “int_c<N> == N_c”); static_assert(four + 3_c == 7_c, "adding"); {tussen}
Filesystem library {tussen}
Paths and functions fs::path : file name manipulation fs:: functions : manipulate files and directories #include <experimental/filesystem> namespace fs = std::experimental::filesystem; using namespace std::literals::string_literals; using namespace std; {tussen}
Path manipulations auto cwd = fs::current_path(); auto assets = cwd / "040coders" / "assets"; cout << cwd << endl; "/Users/john/c++" cout << assets << endl; "/Users/john/c++/040coders/assets" {tussen}
Path components absolute(src): "/Users/john/c++/fs.o" fs::path src("fs.cpp"); root_name: "" cout << src << endl; root_directory: "/" root_path: "/" src.replace_extension(); relative_path: "Users/john/c++/fs.o" cout << src << endl; parent_path: "/Users/john/c++" filename: "fs.o" src.replace_extension(".o"); stem: "fs" cout <<src << endl; extension: ".o" Source: "fs.cpp" For loop: “/Users/john/c++/fs.o" Basename: "fs" "/" Object: "fs.o" "Users" "john" "c++" "fs.o" {tussen}
Directory listings fs::directory_iterator cur_dir(cwd); fs::directory_iterator no_file; "/Users/john/c++/clone" for(auto f: cur_dir){ "/Users/john/c++/clone.cpp" "/Users/john/c++/clone.dSYM" cout << f << endl; "/Users/john/c++/fs" } "/Users/john/c++/fs.cpp" "/Users/john/c++/fs.dSYM" for_each(begin(cur_dir), end(cur_dir), [](const auto& f) { cout << f << endl; }); {tussen}
Recommend
More recommend