Новый стандарт C++: C++09, Что нас ожидает...

Новый стандарт C++: C++09, Что нас ожидает... К октябрю 2007 года комитет запланировал публикацию законченного черновика стандарта C++09(который будет доступен публике для рассмотрения и критики). В октябре 2008 комитет внесёт окончательные коррективы в стандарт и, наконец, на 2009 год запланированна публикация нового стандарта «ISO/IEC 14883(2009): Programming Language C++». Маленький обзорчик ожидаемых вкусностей, которые готовит нам новый стандарт. Итак, в кратце, крупные нововведения следующие: * rvalue references * template aliases * variadic templates * concepts * unicode characters/strings * initializer lists
Rvalue References Появились т.н. ссылки на rvalue. Сначала поясню зачем их вообще изобрели. Исходных проблемы было две: forwarding problem и move semantics. Forwarding problem Эта проблема заключается в том, что текущий стандарт, для заданного выражения E(a1,a2,...,aN), которое зависит от параметров a1,a2,...,aN, не позволяет написать такую ф-цию(или функтор), которая будет эквивалентна этому выражению. Проблема актуальна для разного рода шаблонных обёрток, фабрик, обобщённых функторов и т.п. За идеал перенаправляющей ф-ции(perfect fowarding function) f(a1,a2,...,aN), которая вызывает g(a1,a2,...,aN) взяли следующие критерии: * Для всех наборов a1,a2,...,aN, для которых запись g(a1,a2,...,aN) корректна(well-formed), запись f(a1,a2,...,aN) должна быть так же корректна. * Для всех наборов a1,a2,...,aN, для которых запись g(a1,a2,...,aN) некорректна(ill-formed), запись f(a1,a2,...,aN) должна быть так же некорректна. * Количество работы, которую придётся проделать для реализации такой идеально-перенаправляющей ф-ции f должно не более чем линейно зависеть от N. Вот простейший пример: template void f(T1 &a1, T2 &a2, T3 &a3) { g(a1, a2, a3); } Всё бы хорошо, но нельзя сделать вызов f(1, 2, 3). template void f(const T1 &a1, const T2 &a2, const T3 &a3) { g(a1, a2, a3); } Можно сделать вызов f(1, 2, 3), но, если g хотя бы для одного из параметров берёт неконстантную ссылку, то — облом. template<class /> void f(A1 & a1) { g(a1); } template<class /> void f(A1 const & a1) { g(a1); } Для перегруженного варианта всё отлично, кроме 3-го пункта, а именно, при росте числа параметров N, кол-во ф-ций, которые придётся написать, равное 2N, будет расти совсем нелинейно. Короче говоря, текущий стандарт решить эту проблему не позволяет. Move semantics С++ — язык, построенный на семантике копирования(copy semantics). Что такое семантика перемещения(move semantics)? Хороший пример — std::auto_ptr. Его конструктор копирования берёт неконстантную ссылку и перемещает хранимую в исходном объекте сущность в новый объект(тем самым избегая глубокого копирования). Но, несмотря на то, что конструктор копирования auto_ptr берёт неконстантную ссылку, его суть не в том, чтобы изменить объект, а в том, чтобы переместить к себе его содержимое. Так же, семантика перемещения не помешала бы строкам. Вообразим, что строки у нас без подсчёта ссылок. Теперь вообразим, сколько ресурсов будет затрачено на вычисление такого выражения: string s = string(«123»)+«234»+«567»+«678»+«789»; будет создано как минимум 5 временных объектов и потом ещё произойдёт глубокое копирование результирующей строки в s(если нету подсчёта ссылок). А теперь, вообразим, как было бы прекрасно, если бы конструктор копирования умел бы отличать какой объект ему подсунули — временный или нет. Действительно, о временных объектах можно не волноваться и с чистой совестью «забирать» у них выделеный ими буфер, без необходимости глубокого копирования. К слову, эту проблему можно решить текущими возможностями языка, но очень уж некрасиво... Что же нам предлагает новый стандарт? А предлагает он следующее: ввести новый тип ссылок — rvalue reference. Синтаксис: T t; // lvalue T &rt = t; // lvalue reference T &rrt = t; // rvalue reference // правила сворачивания ссылок T cv1 & cv2 & T cv12 & T cv1 & cv2 && T cv12 & T cv1 && cv2 & T cv12 & T cv1 && cv2 && T cv12 && Любая именованная rvalue-ссылка трактуется как lvalue. Любая неименованная rvalue-ссылка трактуется как rvalue. Т.к. теперь появилась возможность различать тип выражения(lvalue или rvalue), появилась и возможность кастовать lvalue к rvalue: static_cast<T />(lval) будет трактоваться как rvalue. Возвращаемое значение из ф-ции интерпретируется как rvalue т. е. return val; return static_cast(val); Т.о. можно избежать глубокого копирования и ограничиться только лишь перемещением из возвращающей ф-ции в вызвавшую(при наличии соответствующего конструктора). Forwarding problem решается теперь следующим образом: void g(long & a1) { ++a1; } template<class /> void f(A1 && a1) { g(static_cast<A1 />(a1)); } int i = 5; g(i); //fails — int & to long & — запрещённый каст ещё в C++03 f(i); //fails // A1 выводится(deduced) как int & // A1 && int & && int & // a1 — lvalue-reference of int // static_cast<int />(a1) — lvalue-reference of int // f(i) не компилируется по тем же причинам, что и не компилируется g(i) g(1L); // fails — rvalue of long to long & — запрещённый каст ещё в C++03 f(1L); // fails // A1 выводится как long // a1 — lvalue of long(named rvalue-reference lvalue) // static_cast<long />(a1) — rvalue of long(lvalue to rvalue cast) // f(1L) не компилируется т.к. rvalue to non-const lvalue-reference — запрещённый каст ещё в C++03 long L; g(L); // ok f(L); // ok // A1 выводится как long & // A1 && long & && long & // a1 — lvalue-reference of long // static_cast<long />(a1) — lvalue-reference of long // f(L) компилируется(как и должна) Move semantics обеспечивается следующим образом: class string { public: string(const string &); // copy constructor string(string &&); // move constructor string &operator +=(string &); // copy semantics operator += string &&operator +=(string &&); // move semantics opertor += }; string &&operator +(string &&s1, string &&s2) { return s1 += s2; // т.к. s1 — временный объект, мы не создаём новую строку, мы модифицируем существующую } В случаях, когда необходимо вызвать конструктор перемещения для объекта, который не является rvalue, можно сделать каст, запросив необходимое поведение следующим образом: string s1(«abc»); string s2 = s1; // construct s2 as s1 copy string s3 = static_cast<string />(s1); // move from s1 to s2 Лично я эту фичу считаю очень полезной. Особенно, учитывая появившуюся возможность отличать временные объекты от невременных таким образом увеличив производительность в разы, избавившись от лишних операций копирования. Template aliases Думаю все оценят эту фичу. Проблем, побудивших ввести алиасы две. Первая заключается в том, что очень часто появляется нужда в «шаблонном typedef'е». Wrokaround'ом этой проблемы как правило является следующая конструкция: template struct MyVector { typedef std::vector type; }; MyVector::type vec; // не очень красивая запись Вторая же проблема выражается в том, что при использовании вышеобозначенного workaround'а перестаёт работать вывод шаблонных параметров. template void f(std::vector &) { } template void f2(typename MyVector::type &) { } std::vector v; MyVector::type v2; f(v); // ok f2(v2); // ill-formed Алиасы позволяют решить обе проблемы. Алиасы представляют из себя объявления. Они не определяют новых типов. template using MyVector = std::vector; using MyFloat = float; void f1(float) { } // ok void f1(MyFloat) { } // ill-formed — redefinition Шаблонные алиасы нельзя специализировать, но, можно специализировать тип синонимом которого является алиас. Variadic templates Это нововведение избавляет программиста, реализующего библиотеку списков типов или библиотеку, подобную boost::bind от реализации всех возможных вариаций типа template unspecified bind(...); template unspecified bind(...); template unspecified bind(...); // ... template unspecified bind(...); И позволяет сделать шаблон, принимающий переменное количество шаблонных параметров: template // здесь троеточие — это синтаксический элемент R f(Args… args) { return g(args...); // вызываем g, передавая ей все аргументы. } Как к типам(Args), так и к экземплярам этих типов(args) можно применять разные операторы. template R fwd_by_pointer(Args &… args) // R fwd_by_pointer(Arg1 & arg1, Arg2 & arg2, ..., ArgN & argN) { return g(&args...); // return g(&arg1, &arg2, ..., &argN); } Количество типов в наборе можно узнать с помощью нового оператора sizeof...: template struct S { enum { result = sizeof...(Types) }; }; Языковых средств для вытягивания типов из набора(Args) нету, но, это не очень сложно делается руками(и уже сделано в стандартной библиотеке — std::tuple и иже с ним). Языковых средств для вытягивания значения из набора(args) вроде как нету, но, опять же, руками это делается несложно — std::tuple тому пример. В документах встречалось упоминание, что значение можно вытянуть как из массива(args[3], к примеру), но в грамматике я такого упоминания не нашел. Concepts Ну это вообще просто сказка :) Пару слов про сами концепции. Любой, кто использовал обобщённые алгоритмы/структуры данных сталкивался с разного рода требованиями к обобщаемому типу. Наиболее распространенные: DefaultConstructible, CopyConstructible, LessThanComparable. Также, концепциями являются InputIterator, OutputIterator, ForwardIterator, etc. Короче говоря, это требования к обобщаемому типу, невыполнение которых может привести к ошибке инстанцирования шаблона. На данный момент такие требования повсеместно встречаются в документации(IS, boost docs, etc). Теперь эти требования можно будет выражать в коде. Какие проблемы решат концепции? Ну, во-первых, это, конечно то, что теперь, тип будет сначала проверятся на соответствие концепции и только после удачного завершения этой проверки, произойдёт попытка инстанцирования шаблона. Т.о. если тип не LessThanComparable, то при попытке использовать его в контейнере map(к примеру) не придётся втыкать на километры выданных компилятором ошибок. Ошибка будет выглядеть примерно так: «тип T не является LessThanComparable», что, замечу, большой плюс. Все, кто использовал boost::bind/lambda::bind оценят :) Во-вторых, для компилируемого на данный момент клиентского кода, увеличится устойчивость к будущим изменениям в коде библиотеки(гарантии на завтрашний день) — если требование раньше было всего лишь словами и только в следующей версии библиотеки эти слова воплотили в жизнь, то без концепций, некоторый клиентский код может перестать работать, чего не скажешь о коде защищенном концепциями — даже если шаблон мог бы быть инстанцирован, но тип не прошёл проверок на соответствие концепциям, то будет выдана ошибка. В-третьих, писать обобщённый код станет проще. С концепциями можно делать что только душе угодно. К примеру, если тип vector не соответствует концепции Stack(у него нету ф-ций push/pop), но, принципиально его можно использовать как тип соответствующий этой концепции(можно использовать ф-ции push_back/pop_back), то, без потери для общности, можно написать что-то вроде адаптера(concept_map), который будет приспосабливать данный тип к заданной концепции. Концепциями можно защитить не весь класс, а только некоторые его методы. Также, можно разработать несколько версий алгоритма эффективных для той или иной концепции и перегрузить его так, что будет выбран наиболее подходящий алгоритм. Синтаксис концепций интуитивно понятен и поясню я только некоторые моменты. // вот так определяются концепции auto concept LessThanComparable { bool operator<(T, T); }; template // вот так предъявляются требования к типу T const T& min(const T& x, const T& y) { return x < y? x: y; } template where LessThanComparable // или можно предъявить требования так const T& min(const T& x, const T& y) { return x < y? x: y; } // пример более объёмной концепции auto concept Regular { T::T(); // default constructor T::T(const T&); // copy constructor T::~T(); // destructor T& operator=(T&, const T&); // copy assignment bool operator==(T, T); // equality comparison bool operator!=(T, T); // inequality comparison void swap(T&, T&); // swap }; // ещё пример auto concept Convertible /> { operator U(T); }; template where Convertible // концепции можно использовать для задания некоторых взаимоотношений между несколькими типами U convert(const T& t) { return t; } // итератор auto concept InputIterator { typename value_type; // ассоциированные типы typename reference; typename pointer; typename difference_type; where Regular<Iter />; // вложенные требования where Convertible; reference operator*(Iter); // dereference Iter& operator++(Iter&); // pre-increment Iter operator++(Iter&, int); // post-increment // ... }; template /> where Regular Iter find(Iter first, Iter last, const Iter::value_type& value) { while (first != last && *first != value) ++first; return first; } auto concept BinaryFunction/> { typename result_type; result_type operator()(F&, T1, T2); }; auto concept BinaryPredicate/> : BinaryFunction // пример «наследования» концепций { where Convertible; }; // уточнение для char * у которого нету ассоциированных с ним типов // аналог traits, только намного более мощный(см. далее) concept_map InputIterator { typedef char value_type ; typedef char& reference ; typedef char* pointer ; typedef std:: ptrdiff_t difference_type ; }; concept Stack/> { typename value_type; void push(X&, value type); void pop(X&); value type top(const X&); bool empty(const X&); }; // пример адаптации вектора к концепции Stack template/> concept_map Stack< std::vector<T /> > { typedef T value_type; void push(std:: vector<T />& v, T x) { v. push_back(x); } void pop(std:: vector<T />& v) { v. pop_back(); } T top(const std:: vector<T />& v) { return v.back(); } bool empty(const std::vector<T />& v) { return v.empty(); } }; // концепция, которой удовлетворяет вектор(и не только) concept BackInsertionSequence/> { typename value_type = X::value type; void X::push_back(value type); void X::pop_back(); value_type& X::back(); const value_type& X::back() const; bool X::empty() const; }; // пример, как можно адаптировать любой тип, удовлетворяющий концепции C1, к концепции C2. // другими словами, как адаптировать одну концепцию к другой template/> concept_map Stack<X /> { typedef X::value_type value_type; void push(X& x, value_type value ) { x. push_back(value); } void pop(X& x) { x. pop_back(); } T top(const X& x) { return x.back(); } bool empty(const X& x) { return x.empty(); } }; // пример перегрузки на основе концепций — будет выбрана самая «специфичная» форма //т.е. для BidirectionalIterator будет выбран второй вариант, несмотря на то, что удовлетворяет и первый(InputIterator) template/> void advance(Iter& x, Iter::difference type n) { while (n > 0) { ++x; --n; } } template/> void advance(Iter& x, Iter::difference type n) { if (n > 0) while (n > 0) { ++x; --n; } else while (n < 0) { --x; ++n; } } template/> void advance(Iter& x, Iter::difference type n) { x += n; } // пример разных реализаций контейнера для разных хранимых типов данных template/> class dictionary { // slow, linked-list implementation }; template/> where !Hashable<T /> class dictionary<T /> { // balanced binary tree implementation }; template/> class dictionary<T /> { // hash table implementation }; // пример, как можно обложить ограничениями не весь класс, а только некоторые ф-ции(причём разными ограничениями) template/> struct pair { where DefaultConstructible<T /> && DefaultConstructible<U /> pair(): first(), second() { } where CopyConstructible<T /> && CopyConstructible<U /> pair(const T& t, const U& u): first(t), second(u) { } where Destructible<T /> && Destructible<U /> ~pair() { } where Assignable<T /> && Assignable<U /> pair& operator=(const pair& other) { first = other.first; second = other.second; } T first; U second; }; // ещё пример, как помимо CopyConstructible, может понадобится DefaultConstructible // но вектор может ф-ционировать и без второго требования потому его(требование) относят только к отдельной ф-ции. template/> class vector { public: // обратите внимание, как одна ф-ция разделилась на две, дабы добавить контейнеру общности :) // vector(size t n, const T& value = T()); vector(size t n, const T& value); where DefaultConstructible<T /> vector(size t n); }; Ключевое слово where в последней версии вроде как решили заменить на слово requires. Unicode characters/strings Ну, собственно, ничего интересного, кроме самого факта: теперь в С++ оффициальная поддержка UTF-16(u"...") и UTF-32(U"..."). Ну а факт, я считаю, немаловажный и вполне достойный соответствующего внимания со стороны публики :) Появились новые типы char16_t и char32_t. Также, отдельно рассматривается добавление UTF-8(E"..."). Initializer lists X t1 = v; // «copy initialization» possibly copy construction X t2(v); // direct initialization X t3 = { v }; // initialize using initializer list <<<================= X t4 = X(v); // make an X from v and copy it to t4 Достаточно обширное нововведение. Пока всех подробностей не выяснил, но, в двух словах постараюсь рассказать. В языках типа C# практикуется такое: f(new char[] {'1', 'a', '-'}); В С++09 предполагается нечто подобное(только без new :)). Теперь можно будет написать std::vector v = { 1, 2, 3, 4, 5 }; Как написать класс, чтобы его можно было вот так инициализировать? #include // этот хэдер предоставляет класс std::initializer_list namespace std { template/> class initializer_list { // representation implementation defined // (probably two pointers or a pointer and a size) // implementation defined constructor public: // default copy construction and copy assignment // no default constructor // default trivial destructor constexpr int size() const; // number of elements const T* begin() const; // first element const T* end() const; // one-past-the-last element }; } class A { public: A(std::initializer_list a) { /*… */ } // ... }; class B { public: B(std::initializer_list a) { /*… */ } // ... }; void f(const A &a); // #1 void f(const B &b); // #2 int main { A a1 = {1, 2, 3}; A a2{2, 3, 4}; A a3; a3 = A{3, 4, 5}; f({1, 2., 3}); // ambiguity f(A{1, 2., 3}); // #1 f(B{1, 2., 3}); // #2 f({1., 2., 3.}); // #2 f{'a', 'b', 'c'}; // #1 return 0; } Синтаксические мелочи static_assert Новое ключевое слово, позволяет во время компиляции сделать проверку и, в случае чего, сгенерить ошибку компиляции(текст ошибки можно указывать). Наибольшее применение, имхо, будет иметь в шаблонах, хотя, с появлением концепций — сомнительно :). Так же, возможно использование как замена старой доброй директивы #error. template /> struct Check { static_assert(sizeof(int) second.begin(), e2 = i1->second.end(); i2 != e2; ++i2) for (auto i3 = i2->second.begin(), e3 = i2->second.end(); i3 != e3; ++i3) for(auto i4 = i3->begin(), e4 = i3->end(); i4 != e4; ++i4) { /*… */ } // ещё, появилась штука, ожидаемая под названием typeof. // в C++09 её назвали decltype decltype(container.begin()) i = container.begin(); Extended friend Declarations class C; typedef C Ct; class X1 { friend C; // OK: class C is a friend }; class X2 { friend Ct; // OK: class C is a friend }; class X3 { friend class Ct; // C++09 — ok, C++03 — ill-formed }; Extern templates template class MyVector { /*… */ }; template class MyVector; // explicit instantination extern tempalte class MyVector; // extern explicit instantination сделано для того, чтобы диначическая библиотека могла сделать у себя explicit instantination, а клиент у себя extern explicit instantintaion Right Angle Brackets std::vector<std::set<int>> v; // C++03 — ill-formed, C++09 — well-formed Range-based for-loop int array[5] = { 1,2,3,4,5 }; std::vector vec = { 1, 2, 3, 4, 5 }; // так инициализировать нельзя, но мы это опустим :) for ( auto& x: array ) x *= 2; for ( float x: vec ) std::cout << x << std::endl; C99 Compatibility: __func__ namespace N { void f(); } void N::f() { } // __func__ is «f» struct S { S(): s(__func__) { } // ok, s points to «S» ~S() { } // __func__ is "~S" operator int() { } // __func__ is «conversion operator» template/> int g(); const char *s; }; S operator +(S,S) { } // __func__ is «operator+» template<> int S::g<int />() { } // __func__ is «g» struct S { S(): s(__func__) { } // ok const char *s; }; void f(const char * s = __func__); // error: __func__ is undeclared Generalized Constant Expressions constexpr — новое ключевое слово. Суть нововведения в том, что теперь, например, можно как размерность массива использовать результат, возвращенный ф-цией. struct A { constexpr A(int i): val(i) { } constexpr operator int() { return val; } constexpr operator long() { return 43; } private: int val; }; template<int /> struct X { }; constexpr A a = 42; X<a /> x; // OK: unique conversion to int int ary[a]; // error: ambiguous conversion Explicit Conversion Operators class T { }; class X { public: explicit operator T() const; }; int main() { X x; // Direct initialization: T t4( x ); // Copy initialization: T t8 = x; // error // Cast notation: T t12 = (T) x; // Static_cast: T t16 = static_cast<T />( x ); // Function-style cast: T t20 = T( x ); return 0; } Raw String Literals char *s1 = "('(?:[^\\\\']|\\\\.)*'|\"(?:[^\\\\\"]|\\\\.)*\")|"; char *s2 = R"[('(?:[^\\']|\\.)*'|"(?:[^\\"]|\\.)*")|]" // кто работал с regex на с++ — оценят :) // post: strcmp(s1, s2) == 0 char *s3 = " " " " «Auto-generated html formated source » " " " " " " " " "<PRE /> "; char *s4 = R"[\ Auto-generated html formated source <PRE /> ]" // post: strcmp(s3, s4) == 0 A name for the null pointer: nullptr char* ch = nullptr; // ch has the null pointer value char* ch2 = 0; // ch2 has the null pointer value int n = nullptr; // error int n2 = 0; // n2 is zero if( ch == 0 ); // evaluates to true if( ch == nullptr ); // evaluates to true if( ch ); // evaluates to false if( n2 == 0 ); // evaluates to true if( n2 == nullptr ); // error if( nullptr ); // error, no conversion to bool if( nullptr == 0 ); // error // arithmetic nullptr = 0; // error, nullptr is not an lvalue nullptr + 2; // error Alignment Support // новые ключевые слова: alignas, alignof const std::size_t align_of_int = alignof(int); T alignas(T) alignas(long) t1; T alignas(T) alignas(align_of_int) t2; Prohibited access specifier template struct owned_ptr { public: explicit owned_ptr( T * p ): pt( p ) {} ~owned_ptr() { delete pt; } T * operator->() { return pt; } T const * operator->() const { return pt; } private: T * pt; void foo(); prohibited: owned_ptr( owned_ptr const & ); owned_ptr & operator=( owned_ptr const & ); }; template void S::foo() { new owned_ptr(*this); // compile-time error(не link-time) } Explicit class and default definitions class A explicit { // no implicitly declared/defined special member functions(default ctor, copy ctor, copy assignment operator, destructor) }; class B explicit { public: B() {default} // default ctor definition(compiler generated) }; class I explicit { public: virtual ~I() {default} }; Defaulted and Deleted Functions struct type { type() = default; // trivial virtual ~type() = default; // non-trivial because virtual type & operator =( const type & ); // declaration and.... }; inline // the inline definition keeps it trivial type & type::operator =( const type & ) = default; // -------------------------------------------------------------- struct type { type( const type & ); // declaration and.... }; type::type() = default; // the non-inline makes it non-trivial // -------------------------------------------------------------- struct type { type & operator =( const type & ) = delete; type( const type & ) = delete; type() = default; }; // -------------------------------------------------------------- struct type { void * operator new( std::size_t ) = delete; }; // -------------------------------------------------------------- struct type { ~type() = delete; // disable destructor }; // -------------------------------------------------------------- struct type { type( long long ); // can initialize with an long long type( long ) = delete; // but not anything less }; extern void bar( type, long long ); // and the same for bad overloads void bar( type, long ) = delete; // of free functions // -------------------------------------------------------------- struct type { type( long long ); explicit type( long ) = delete; }; extern void function( type ); function( type( 42 ) ); // error 42 promotes to long function( 42 ); // okay type(long long); type(long) not considered Pure implementation method declaration struct Base { virtual void f1() = 0; virtual void f2() = 0; }; struct S : public Base { virtual void f1() > 0; // должно быть определение S::f1, иначе compile-time error virtual void f2() >= 0; // определение S::f2 может быть, а может и не быть :) virtual void f3() > 0; // compile-time error — нету объявления Base::f3. virtual void f4() >= 0; // compile-time error — нету объявления Base::f3. }; Strongly Typed Enums enum class E { E1, E2, E3 = 100, E4 /* = 101 */ }; void f( E e ) { if( e >= 100 ); // error: no E to int conversion } int i = E::E2; // error: no E to int conversion // ------------------------------------------------------ enum class E { E1, E2, E3 = 100, E4 /* = 101 */ }; E e1 = E1; // error E e2 = E::E2; // ok // ------------------------------------------------------ enum class E: unsigned long { E1 = 1, E2 = 2, Ebig = 0xFFFFFFF0U }; unsigned long ul = E::Ebig; Формальные мелочи Conditionally-Supported Behavior Добавлен новый вид определяемого стандартом поведения. Теперь, конструкции для которых поведение было неопределено(UB), считаются conditionally-supported и могут интерпретировать либо как implementation-defined, либо как ill-formed. Замена некоторых UB на Diagnosable Errors К примеру, теперь передача non-POD в элипсис приведёт к ошибке компиляции, а не к UB как в C++03. Новая модель выполнения программы В связи с добавлением оффициальной поддержки multithreading. Убрали понятие sequence point. Добавили понятие evaluation — набор выборок(чтение значения переменной) и side effects, которые происходят в ходе вычисления выражения. Понятие sequence point заменили аж тремя понятиями sequencing constraints: sequenced before, unsequenced, indeterminately sequenced. Эти понятия — отношения между двумя evaluations A и B(A sequenced before B, A and B unsequenced, etc). Теперь порядок вычисления операндов не unspecified. Теперь evaluations of operands unsequenced :) В связи с отсутствием понятия sequence point вычисление операндов операторов «a && b», «a || b», «a? b: c» и «a, b» примерно следующее: evaluation of a is sequenced before evaluation of b. Облегчение ограничений на POD'ы Ввели два новых понятия: trivial-class и standard-layout-class. POD — это класс, который является одновременно и trivial и standard-layout. Теперь все гарантии, которые давал POD можно разделить на 2 части: первые даются для trivial типов, вторые для standard-layout. В общем теперь большее кол-во типов будет поддаваться копированию посредством memcpy и т.п. Перегрузка операторов Рассматривается возможность перегрузки операторов . .* static_cast<> const_cast<> dynamic_cast<> Стандартная библиотека Дополнение к этому пункту и/или более подробные описания фич можно увидеть здесь: Новый стандарт C++. C++09 (сообщение #1601275) cstdint из C99 Добавленна опциональная поддержка типов с размером точно соответствующим указанному. int8_t, int16_t, int32_t, int64_t uint8_t, uint16_t, uint32_t, uint64_t Обязательная поддержка для типов с размером не меньшим указанного. int_least8_t, int_least16_t, etc. uint_least8_t, etc. И обязательная поддержка типов с размером точно соответствующим указанному, но, возможно, более быстрых, чем их least-эквиваленты. int_fast8_t, etc. uint_fast8_t, etc. Контейнеры Sequence container: std::array — см. ниже «Перешло из boost». Unordered associative containers: unordered_map, unordered_multimap, unordered_set, unordered_multiset Вполне ожидаемые контейнеры работающие по принципу хэширования, ранее известные под названием hash_set/map в «вольных» реализациях STLport, MS VC-8.0. В связи с введением rvalue-reference и move semantics Во-первых, повсеместное добавление/переведение вышеобозначенной семантики для повышения производительности(там, где это возможно). Добавлены ф-ции помошники move и forward, означающие не что иное, как прямое предназначение rvalue-ссылок. Первая вынуждает использовать семантику перемещения даже если операнд — lvalue(-reference). Вторая осуществляет необходимые телодвижения для достижения perfect forwarding :) Добавлен move_iterator, который работает точно также, как Iter, за исключением того, что его dereferencing оператор принуждает использовать семантику перемещения. В связи с введением constexpr Много где встречаются эти константные ф-ции(результат которых можно использовать даже для определения статического массива). К примеру numeric_limits. Теперь его ф-ции min/max отвечают соответствующим требованиям. Перешло из boost std::tuple Тож самое, что и boost::tuple, за одним отличием — переведён на синтаксис variadic templates. std::bind Тож самое, что и boost::bind, за одним отличием — переведён на синтаксис variadic templates. std::array(sequence container) Тож самое, что и boost::array. Вроде где-то упоминалось, что собираются сделать его N-мерным(в отличие от 1-мерного boost::array). std::regex См. boost::regex Многопоточность Ничего не могу сказать более определённого, чем то, что в новом С++ будет поддержка многопоточности и будет предоставленно API, совместимое с posix pthreads. Также, возможность выполнения атомарных операций(необходимо для синхронизации — реализации спин-локов)
  • +8
  • 15 декабря 2008, 17:21
  • azazello

Комментарии (11)

RSSсвернуть /развернуть
+
+1
  че за хрень
avatar

SYLOR

  • 15 декабря 2008, 17:57
+
+4
Аааа мой комп в ауте от этого
avatar

Jedi_Knight

  • 15 декабря 2008, 18:40
+
+2
Мой мосг в ауте, хотя много интересного .
Они про Си забыли? C99 онли под линух, под виндас только через эмули =(
avatar

Psihx

  • 15 декабря 2008, 19:27
+
+4
респект тем людям кто это смог прочитать…
З.Ы. я не смог)
avatar

LosTic

  • 15 декабря 2008, 20:23
+
+1
ааааааааа, мой моск взорвалсо
avatar

chudnyj-fejs

  • 15 декабря 2008, 20:38
+
+2
мдя… что-то не похоже на информационно-развлекательный портал
avatar

smiq

  • 15 декабря 2008, 22:32
+
+2
agМне камент ыбольше чем новость нравятся )
avatar

sLaWa

  • 15 декабря 2008, 23:07
+
0
LosTic,
ag
avatar

M4

  • 16 декабря 2008, 00:05
+
0
эээ… хм… мне вообще жестко понравилось!!! Давай побольше таких!!! Еще есть что нибудь вот про
}
template
void advance(Iter& x, Iter::difference type n)
{
if (n > 0) while (n > 0) { ++x; --n; }
else while (n < 0) { --x; ++n; }
}
template
void advance(Iter& x, Iter::difference type n)
{
x += n;

?????????????
avatar

chet

  • 16 декабря 2008, 01:23
+
0
афтор, слышишь?, никогда,  слышишь?!  не пости эту хрень тут!!!
avatar

-RoveR-

  • 16 декабря 2008, 02:27
+
0
аффтар зачет, самое то, что все ждали на развлекательном портале
avatar

VovanS

  • 16 декабря 2008, 17:41

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.
Валидный HTMLВалидный CSSRambler's Top100