References:
Syntax highlighting - http://tohtml.com/
Notes are based on this lections http://www.aristeia.com/C++11.html
Interesting notes, and a lot of references are in: http://www.stroustrup.com/C++11FAQ.html
1. Все контейнеры в c++98 дают basic garantee, а некоторые операции (например std::vector<T>::push_back) дают strong garantee
2. delete incomplete types
class ptr delete ptr; <<< undefined behaviour for incomplete types
Для POD, и для объекта без деструктора будет выполнено что-то вроде C-rutime free, которому не требуется знание о размере объекта.
В этом случае вам повезло, и ваш delete ptr сработает в реальных реализациях C++ runtime.
3. refrence collapsing
Стандартом разрешен refrence collapsing в template-ах. Разрешено коллапсить T&& => T&
template <class T>void f(T& val){ val = 0;}int i = 0; f<int&>(i);
4. cv (const-volatile) for value-type (not for ptrs or references) args in tempate deduction is ignored,
array and functions decay to pointers
5. auto - выводимый тип на подобие template-ого, но работающий в функциях и for для массивов.
Для auto вывод идентичен тому, как происходит вывод для аргументов шаблонной функции.
auto v1(expr); // direct initializationauto v2=expr; // copy initialization
int arr[] = {1,2,3};for (auto x:arr){ printf("%i\n", x);}
Auto можно использовать вместе с const/volatile и Pointer/reference, i.e.:
int ii= 1;
const auto * p_ii = ⅈ
const auto& p_ref = ii;
Для for появился новый синтаксис - range based for loop:
for (auto i : v) std::cout << i;
Range-Based for Loops valid for any type supporting the notion of a range: obj.begin() and obj.end() or begin(obj) and end(obj) should be valid
6. Изначально в C null pointer constant - это целое выражение со значением ноль, или преобразованное такое к (void*).
Если определить NULL как целое в стандартной библиотеке, то f(NULL) будет искать функцию f принимающую int.
Если определить NULL как ((void*)0) , то для f(NULL) будет отсутствовать неявное кастование к (int*), так что такой NULL передать в функцию принимающую int* без явного кастования скорее всего не выйдет.
В C++11 на замену NULL пришёл nullptr.
7. При инстанцировании шаблона теперь не обязательно делать пробел в >>, а так же в случае указания интегрального типа в параметре шаблона можно выполнить в right-shift >>. Для этого надо заключить выражение в круглые скобки.
template <class T, int size>class AA {}; AA<std::vector<int>>, 2> obj;
8. Strongly typed enums (или scoped enums)
- Для них нет кастования неявного в int - Они определяют своё пространство имён - Для них (и для обычных enum кстати теперь тоже) можно указывать underlying тип (в этом случае получаемая концепция называется Enhanced Enums)
По умолчанию этот тип для scoped enums есть int.
enum class Color : int{red,green,blue};
- Для обычных enum в C++11 как и в C++98 по-умолчанию про underlying тип ничего не говорится
- Можно делать forward declaration для enum-ов, если указан underlying type.
Для обычных enum в C++11, C++98 этого делать нельзя.
Microsoft compiler allow forward declaration of enum, but it is only MS extension, it is not standart!
enum ForwardDeclare:std::uint8_t;
У Страуструпа отмечено, что можно использоваться теперь в явном виде(опциоанально) имя обычного енума его имя, для обращения к его элементам как бы через пространство имён нового типа.
9. Поддержка Unicode
Символы
char16_t, char32_t - symbols with at least 16, 32 bits.
UCS-2, UCS-4
u'a' -- ucs2 (pretty like UTF-16, but surrogate pairs are not supported in UCS-2)
U'a' -- ucs4 (UTF-32)
wchar_t -- остался.
Строки
u"a" -- UTF-16 строка. С поддержкой surrogate pairs!
U"a" -- UTF-32 строка
u8 "UTF8 string" -- utf8 строка
u8 "UTF8 string" chars in utf8
Управляющие последовательности для unicode
\u2620 -- черепок с костями! ( python -c "print u'\u2620'" )
\UFFFFFFFF (кажется было в C99)
std::string, std::wstring, std::u16string, std::u32string -- typedefs на std::basic_string
10. Поддержка конвертации между типами
std::codecvt<>
11. Появились raw string как в python.
R"(asd\n)", аналог питоновского r"""str str""". Для таких строк поддерживается multiline. Есть фишечка как указывать delimiter для строк.
12. В C++98 есть куча видов инициализации
const int v1(expr); // direct initializationint v2=expr; // copy initializationint arr[]={1,2,3}; // bracket initialization
13. C++11 give a new type of initialization - uniform initialization -- bracket initialization for ALL
int a = {1};std::vector<int> a {1,2,3};int a[] {1,8,8};
14. In C++98 constant member arrays and heap arrays are impossible to init.
15. C++11 std::initializer_list<T>
New concept in
int a[] {1,8,8}
{1,8,8} -- it is initialization list. Implicitly casting to std::initializer_list<T>. Ctor with initialization list argument has priority during overloading. Type deduction in template functions not works for implicitly std::initializer_list type. But for auto works fine. It is one place where auto != template
// gcc -x c++ -std=c++11 t.cpp#include <stdio.h>#include <initializer_list> template <class T> void f1(T a) {}void f2(std::initializer_list<int> a) {}
int main(){// f1({1,2,3}); // DOES NOT COMPILE f2({1,2,3}); auto f3 = {1,2,3}; return 0;}
16. aggregates & non-aggregates
aggregates -- array, structs. similar as in C. If you have too many initalization=> not compile if less - rest is default-init
non-aggregates -- need ctor. If you have too many or fewer initalization=> not compile
17. Можно явно заставить компилятор сгенерировать код по-умолчания для метода, для которых такое поведение может иметь место быть через =default.
Можно запретить использовать функцию/метод указав =delete
Copy of my answer: https://stackoverflow.com/questions/7627098/what-is-a-lambda-expression-in-c11/30625943#30625943
closure in math set with its boundary (functional analysis) or family function which can be achieved via constructing all possible formula under basis function (disrete math)
But in C++ it's object (instance of the class) with:
ret_type operator()(<list of arguments>) const
Created by compiler during parsing lambda expression. Which is written in form "[](int arg1){}".
Lambda's in fact generate C++ classes with operator(). Closure в некотором смысле похоже на bind
1. Captured values. What you can capture
1.1. You can refer to variables with static storage duration in lamdas. They all are captured.
1.2. You can use lambda to capture values "by value". In such a case captured vars will be copied to a function object (closure).
[captureVar1,captureVar2](int arg1){}
1.3. You can capture it by reference. & -- in this context mean reference, not pointers
[&captureVar1,&captureVar2](int arg1){}
1.4. It exists notation to capture all non-static vars by value, or by reference
[=](int arg1){} // capture all not-static vars by value [&](int arg1){} // capture all not-static vars by reference
1.5. It exists notation to capture all non-static vars by value, or by reference and specify smth. more Example of capture all not-static vars by reference, but by value capture Param2
[&,Param2](int arg1){}
2. Return type deduction
2.1. Lambda return type can be deduced if lambda is one expression. Or you can explicitly specify it.
[=](int arg1)->trailing_return_type{return trailing_return_type();}
If lambda has more than one expression, then the return type must be specified via the trailing return type.
Also, similar syntax can be applied to auto functions and member-functions
p.s. The suffix syntax is not primarily about templates and type deduction, it is really about scope.
One more example when it was useful (http://www.stroustrup.com/C++11FAQ.html)
template<class T, class U> auto mul(T x, U y) -> decltype(x*y) { return x*y; }
We use the notation auto to mean "return type to be deduced or specified later."
3-. Captured values. What you can not capture
3.1 You can capture only local vars, not member variables of the object.
3.2 You can allow lambda to modify captured values
int x = 12;
auto a = [=]() mutable ->void { x = 1; };
3.3 You can capture this pointer explicitly
auto a = [this]() ->void { aa = 1; };
or implicitly, because default capture also makes this available.
auto a = [=]() ->void { aa = 1; };
4. Сonversions
4.1. lambda is not a function pointer and it is not an anonymous function, but capture-less lambdas can be implicitly converted to a function pointer
5. Extra
5.1 In C++14 the extra feature which has a name is "init capture". It has been added. It allows to perform arbitrarily declaration of closure data members:
auto interpolate = [min = toFloat(0), max = toFloat(255)](int value)->float { return (value - min) / (max - min);};
template <class T>
using MyAllocVec = std::vector<T, MyAllocator>; // MyAllocVec is alias template
- Cannot be partially specialized
- Can be used wherever typedef is used
19. Concurrency support in C++11.
Threads
All things that can be executed can be passed to std::thread. (For example, you can pass function, function objects, and lambdas.)
How to pass arguments:
A. std::thread’s variadic constructor (conceptually) copies everything
B. Or to "pass "arguments, a lambda can be used instead which captures everything in the closure object
При задании параметров конструктору std::thread происходит копирование объектов внутрь std::thread.
Если запускаемая функция принимает reference, то это будет reference на копию объекта.
При задании lamda функции std::thread-у происходит создание closure, и затем этот closure копируется внутрь std::thread
Лучше передавать значения в lambda по значению для старта потока, или переводить его в join state.
join - ожидание завершения.
Есть специализированная функция std::ref, которая создаёт "reference объект" на объект, который ведёт себя как ref.
Async
Кроме thread есть возможность запустить функцию асинхронно через std::async([]{}), и получить контейнер
с будущим результатом std::future<double> f = std::async([]{return })
f.get() -- Force waiting for the result, and return the result.
get() -- Raise exception if exception occur inside thread execution. So it is like a usual function call.
async -- можно запускать в новом потоке std::async(std::launch::async, entryPoint)
async -- можно запускать в отложенном режиме, std::async(std::launch::deferred, entryPoint)
функция будет вызвана по вызову f.get() в том же потоке кто дёрнул f.get()
Зачем это надо:
-- локализация проблем c multithreading приложением, поменяв policy на std::launch::deferred вы будете пускать всё в одном потоке
-- иногда overhead на создание потока больше чем суть выполняемой работы, так что можно поэкспериментировать, и тем самым подтюнить скорость.
Если не указывать policy, то runtime выберет сам policy. Важно так же, что не существует cancel на std::async.
std::future служит для получение результата одним потоком
std::future::get может быть вызвано один раз, второй раз - кидается exception
std::shared_future для получение результат многими потоками
std::shared_future::get может быть вызвано много раз
средства синхронизации
std::future::wait -- Блокировка в ожидании результата
std::future::wait_for -- Блокировка в ожидании результата с указанием timeout, std::chrono::seconds(0)
std::future::wait_for(std::chrono::seconds(0)) == std::future_status::ready -- Хороший способ проверить статус задачи
std::mutex -- non recursive, not timeout.
std::recurisive_timed_mutex -- recursive timeout mutex.
можно скормить mutex std::lock_guard-у. std::unique_lock -- более гибкий чем std::lock_guard
Для мьютекса нельзя выполнять копирование, перемещение и т.д.
std::lock доступен в C++11 для "одновременной" лочки нескольких объектов синхронизации.
Новый модификатор типа thread_local.
Статические переменные такого типа создаются через ctor перед пуском потока, и умирают по окончанию потока.
shared_ptr -- потоко-безопасный умный указатель, который хранит указатель на данное и блок управления.
Блок управления состоит из:
* счётчик shared
* счётчик weaked
* возможно кастомный аллокатор, кастомный деаллокатор
* информацию о реальном типе
Для этого типа создавать виртуальный деструктор НЕ НУЖНО, в случае кастования shared_ptr<T> => shared_ptr<TBase>
Когда shared_counter == 0 => объект на который указывает указатель уничтожается, и указатель на реальный объект обнуляется.
Когда же shared_counter==0 && weak_counter==0 => уничтожается контрольный блок
weak_ptr -- не влияет на изменяемый shared_counter, нужен для ликвидации циклов. Его можно получить от shared_ptr.
затем когда вы захотите с ним поработать надо будет вызывать lock.
Комитет хочет, чтобы люди использовали shared_ptr:
1) Есть неявное преобразование между типами shared_ptr<Derived>, shared_ptr<Base>
2) Есть всякие std::dynamic_pointer_cast
unique_ptr -- замена auto_ptr. Создавать виртуальный деструктор НУЖНО если вы будете неявно преобразовывать тип имеющегося unique_ptr.
Копирование запрещено, разрешена только std::move семантика. unique_ptr содержит специализацию для массива. В случае массива:
- поддерживается индексная семантика, но нет операторов *, ->
- unique_ptr<Derived[]>, то этот unique_ptr не получится сконвертировать в unique_ptr<Base[]>
Есть обобщение std::pair в виде std::tuple. Введён forward_list - однонаправленный список, однако работа с ним общими средствами STL крайне неудобна.
Есть
std::array // -- обёртка над массивом с fixed-size.
std::array<int,5> arr;
arr.data() // -- raw pointer to start
Правила инициализации как для aggregate типа, или что то же самое как для обычного c-raw-array-я
Добавлена поддержка Regexp-ов.
std::function очень гибок и может хранить, всё что может быть вызвано. (invoke)
std::bind является заменой std::bind1st,std::bind2nd.
Для std::bind появился изощрённый синтаксис с _1,_2... с помощью которого "кодируется" bind аргументов.
Так же можно байндиться к non-static member function. Только при указании параметров надо указывать, что функция принимает n+1 аргумент, где первым идёт this.
Как правило компилятор генерирует лучший код для lambda, а не для bind.
Так же lambda позволяет делать inline. А вот bind использующий указатели на функции - нет.
about std::function template param
move полезно для объектов, которые хранят часть своего стейта в heap. Move-инг никогда не медленнее копирования,
а обычно и быстрее. Для некоторых объектов существует только move семантика:
-- Например thread. Не имеет смысла имплементить move.
-- Если он по скорости хуже или такой же как копирование
-- Эта операция не находится на критическом пути выполнения в программе
(Скот Майерс: "не следует использовать std::swap для реализации move-а. В этом нет никакого смысла.")
В C++98
LValue -- то от чего можно взять адрес. (переменные, или lvalue reference)
RValue -- то от чего нельзя взять адрес (в 99% случаях это безымянные временные переменные)
Хороший контрпример то что является rvalue, но имеет имя -- this
LValue reference -- обычные references
Lvalue may bind to LValue reference
Rvalue may bind to LValue const reference
В C++11
RValue reference -- T&& (C++11). Ведут себя как LValue reference. Цель - иметь кандидата на moving.
Rvalue may bind to a non-const rvalue reference. Lvalue may not bind to an rvalue reference
Важное правило: move из lvalues никогда не выполняется, для него выполняется копирование.
void f(T&&) имеет приоритет над void f(T&), если обе могут быть вызваны.
С++11 считает noexcept -- вызов любого деструктора, аллокация памяти
move self to self -- обычно не проверяется, т.к. это не обычное поведение.
EXPLICIT MOVE REQUEST и первая пугающая вещь
Писать move-конструктор следует аккуратно, дело в том T&& хоть и есть rvalue-reference,
но в контексте тела которое видит "T&& x", x уже является lvalue. Самая путающая вещь в C++11!!!
Поэтому например в списке инициализации надо писать Base(std::move(rhs.base))
std::move -- превращает expression в rvalue.
std::move можно было бы назвать rvalue_cast
ИГРА ВОКРУГ T&& и вторая пугающая вещь
Ещё есть специальная конструкция T&& Param Definition in Template правило действует только для конструкций вида
template <class T>
void f(T&& arg)
{}
arg is Lvalue => deduced to void f<T&> (T& arg)
arg is Rvalue => deduced to void f<T> (T&& arg)
template<class T>
void f(T&&)
{
printf("template call of f() not deduced to rvalue-reference\n");
}
template<>
void f<A>(A&&)
{
printf("template call of f() deduced to rvalue-reference\n");
}
void f(T&& arg) -- trully rvalue reference
template <class T> -- universal reference(Term by Skott Mayers), binds everything
void f(T&& arg)
{}
30. std::move -- unconditional reference value cast.
std::forward -- conditional cast for universal references (universal references -- официально термина нет, введён Скотом Майерсом)
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2080.pdf
template <class T...>
void f(const T&...arg)
Обощение ... для template-ов с переменным кол-ом аргументов шаблона, и переменным кол-ом аргументов
шаблонной функции. Можно ставить пробелы где угодно вокруг ...
Единственный способ получение очередного аргумента шаблона - рекурсивный вызов функции, у которой параметры шаблона указаны как <TExtractType, RestTypes...>
ПОПАХИВАЕТ БЕЗУМИЕМ ФУНКЦИОНАЛЬНЫХ ЯЗЫКОВ ПРОГРАММИРОВАНИЯ
https://en.wikipedia.org/wiki/Variadic_template
class ...Args -- parameters pack
(Arg&&....params) -- function parameters pack
Args... -- unpack parameters
sizeof...(Args) -- sizeof of parameters
Example:
template<typename T, typename... Args>void printf(const char *s, T value, Args... args){ while (*s) { if (*s == '%') { if (*(s + 1) != '%') { std::cout << value; s += 2; printf(s, args...); return; } ++s; } std::cout << *s++; } }
Если есть destructor user defined, то в C++11 никого implicit copy constructor-не генерируется. Все об этом думали с ~92ого года. И только теперь для C++11 ввели это.
1. Должны использоваться в лямбда выражениях для определения типа auto f = [](double d)->double{...}
2. Могут использоваться для обычных функций, чтобы запутать коллег auto f(int x)->void;
3. Могут использоваться чтобы отложить немного определение возвращаемого типа в шаблонных функциях
template<class T, class U>
auto mul(T x, U y) -> decltype(x*y) {return x*y;}
1. constexpr - const during compile time
2. emplace_back - construct object directly in place in memory of the container
3. vector::shrink_to_fit method
4. noexcept specification - like throw() specification for functions from C++98, but it allows more optimization
5. alignas(128) and alignof(x) - операторы для выравнивания встроенные в язык
6. static_assert - assert during compile time
7. explicit - in C++98 it can be used only for ctor to not allow implicit conversion during a call of a constructor. In C++11 it can be used for another type conversion too
8. c++11, generate move if:
-- no user defined: copy or move
-- no user declared dtor
9. Other rules relative to autogenerated special ctors:
user declared copy, move, dtor => warning about implicit copy operation
no user-declared ctor => default ctor generated
no user-declared move operation=> copy operation and operator generated
In the appendix I would like to append the fact from one resource that shows when the compiler generates special member functions in C++11:
https://blog.feabhas.com/2015/11/becoming-a-rule-of-zero-hero/
"The most important aspect of C++11 PODs is that adding or subtracting constructors do not affect layout or performance."