constexpr functionsexchangemake_uniqueoptionalshared_mutex and shared_lockdynarrayreturn statement, you can not specify the type of the return value - the compiler can output it independently. Many were surprised that this feature is not available for normal functions. The corresponding proposal was made before the release of C ++ 11, but it was postponed due to time constraints, and now, several years later, it has been added to the standard. Also, this amendment says that if a function or lambda expression has several return that return the same type, in this case, the compiler must also output the type value automatically, including the case with a recursive call. auto iterate(int len) // - int { for (int i = 0; i < len; ++i) if (search (i)) return i; return -1; } auto h() { return h(); } // , auto sum(int i) { if (i == 1) return i; // - int else return sum(i-1)+i; // } template <class T> auto f(T t) { return t; } // []()->auto& { return f(); } // // foo.h class Foo { public: auto getA() const; }; // foo.cpp #include "foo.h" auto Foo::getA() const { return something; } // main.cpp #include "foo.h" int main() { Foo bar; auto a = bar.getA(); // , } std::initializer_list . #include <memory> #include <iostream> #include <utility> template <class T> void run(T&& runnable) { runnable(); }; int main() { std::unique_ptr<int> result(new int{42}); run([result](){std::cout << *result << std::endl;}); } [ x { move(x) }, y = transform(y, z), foo, bar, baz ] { ... } x will be directly initialized by moving x , y will be initialized by the result of the call transform , and the rest will be captured by value. Another example: int x = 4; auto y = [&r = x, x = x+1]()->int { r += 2; return x+2; }(); // ::x 6, y 7-. [int x = get_x()] { ... } [Container y{get_container()}] { ... } [int z = 5] { ... } [&&x] { ... } auto type specifier meaning a generic (template) lambda parameter void f1(int (*)(int)) { } void f2(char (*)(int)) { } void g(int (*)(int)) { } // #1 void g(char (*)(char)) { } // #2 void h(int (*)(int)) { } // #3 void h(char (*)(int)) { } // #4 auto glambda = [](auto a) { return a; }; f1(glambda); // OK f2(glambda); // : ID g(glambda); // : h(glambda); // OK: #3, ID int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK auto vglambda = [](auto printer) { return [=](auto&& ... ts) { // OK: ts - printer(std::forward<decltype(ts)>(ts)...); }; }; auto p = vglambda( [](auto v1, auto v2, auto v3) { std::cout << v1 << v2 << v3; } ); p(1, 'a', 3.14); // OK: 1a3.14 constexpr functionsconstexpr functions:static , thread_local and uninitialized variables)if and switch (but not goto )for (including range-based for ), while and do-whileconstexpr calculations constexpr int abs(int x) { if (x < 0) x = -x; return x; // OK } constexpr int first(int n) { static int value = n; // : return value; } constexpr int uninit() { int a; // : return a; } constexpr int prev(int x) { return --x; } // OK constexpr int g(int x, int n) { // OK int r = 1; while (--n > 0) r *= x; return r; } constexpr non-static member functions implicitly obtained the const specifier was removed (for more details, click here ).constexpr variable templates for more convenient combination with template algorithms (it is possible to use not only with built-in types, but also with user-defined types): template<typename T> constexpr T pi = T(3.1415926535897932385); template<typename T> T circular_area(T r) { return pi<T> * r * r; } struct matrix_constants { template<typename T> using pauli = hermitian_matrix<T, 2>; template<typename T> constexpr pauli<T> sigma1 = { { 0, 1 }, { 1, 0 } }; template<typename T> constexpr pauli<T> sigma2 = { { 0, -1i }, { 1i, 0 } }; template<typename T> constexpr pauli<T> sigma3 = { { 1, 0 }, { -1, 0 } }; }; exchangeatomic_exchange function, which allows you to assign a new value to the object and return its old value. This function can be useful for ordinary objects. // template<typename T, typename U=T> T exchange(T& obj, U&& new_val) { T old_val = std::move(obj); obj = std::forward<U>(new_val); return old_val; } std::unique_ptr::reset : template<typename T, typename D> void unique_ptr<T, D>::reset(pointer p = pointer()) { pointer old = ptr_; ptr_ = p; if (old) deleter_(old); } template<typename T, typename D> void unique_ptr<T, D>::reset(pointer p = pointer()) { if (pointer old = std::exchange(ptr_, p)) deleter_(old); } make_uniquemake_shared . It allows you to optimize the allocation of memory for shared_ptr , as well as to increase security regarding exceptions. Although a similar optimization for unique_ptr not possible, increased security with respect to exceptions never unique_ptr . For example, here, in both cases, we can get a memory leak if an exception is thrown during the creation of one object, and the second object has already been created but not yet placed in unique_ptr : void foo(std::unique_ptr<A> a, std::unique_ptr<B> b); int main() { foo(new A, new B); foo(std::unique_ptr<A>{new A}, foo(std::unique_ptr<B>{new B}); } make_unique . Thus, C ++ 14 almost completely (with the exception of very rare cases) suggests that programmers abandon the new and delete operators. #include <iostream> #include <string> #include <memory> using namespace std; void foo(std::unique_ptr<string> a, std::unique_ptr<string> b) {} int main() { cout << *make_unique<int>() << endl; cout << *make_unique<int>(1729) << endl; cout << "\"" << *make_unique<string>() << "\"" << endl; cout << "\"" << *make_unique<string>("meow") << "\"" << endl; cout << "\"" << *make_unique<string>(6, 'z') << "\"" << endl; auto up = make_unique<int[]>(5); for (int i = 0; i < 5; ++i) { cout << up[i] << " "; } cout << endl; foo(make_unique<string>(), make_unique<string>()); // auto up1 = make_unique<string[]>("error"); // auto up2 = make_unique<int[]>(10, 20, 30, 40); // auto up3 = make_unique<int[5]>(); // auto up4 = make_unique<int[5]>(11, 22, 33, 44, 55); // } /* Output: 0 1729 "" "meow" "zzzzzz" 0 0 0 0 0 */ std::stringstream ss; std::string original = "foolish me"; std::string round_trip; ss << original; ss >> round_trip; std::cout << original; // : foolish me std::cout << round_trip; // : foolish assert(original == round_trip); // assert std::stringstream ss; std::string original = "foolish me"; std::string round_trip; ss << quoted(original); ss >> quoted(round_trip); std::cout << original; // : foolish me std::cout << round_trip; // : foolish me assert(original == round_trip); // assert std::cout << "She said \"Hi!\""; // : She said "Hi!" std::cout << quoted("She said \"Hi!\""); // : "She said \"Hi!\"" s operator for basic_stringh , min , s , ms , us , ns for types included in chrono :: duration auto mystring = "hello world"s; // std::string auto mytime = 42ns; // chrono::nanoseconds s do not conflict, since they accept different types of parameters.optional optional<int> str2int(string); // , int get_int_form_user() { string s; for (;;) { cin >> s; optional<int> o = str2int(s); // 'o' , if (o) { // 'o' ? return *o; // } } } shared_mutex and shared_lockshared_mutex library designed for this purpose. The lock function provides unique access, and can be used with lock_guard and unique_lock previously added. To get shared access, you need to use the lock_shared function, and it’s better to do this through the shared_lock / RAII class shared_lock : using namespace std; shared_mutex rwmutex; { shared_lock<shared_mutex> read_lock(rwmutex); // } { unique_lock<shared_mutex> write_lock(rwmutex); // lock_guard // } dynarraystd::dynarray , which also recognizes its size at run time and cannot change it further, however, it can either place objects on the stack, or place them in a heap, while having an interface in many ways similar to std::array and std::vector . According to the amendment, this class can be explicitly optimized by the compiler, for use cases of the stack.dynarray and optional have been moved to separate technical specifications.Source: https://habr.com/ru/post/184606/
All Articles