770 likes | 1.01k Views
Développement natif en C++. Christophe Pichaud – Architecte Sogeti Loïc Joly – Architecte CAST. Code / Développement. Design/Général. Code/ Dev. Office / B2B / LOB / entreprise. Mobilité/Consumer/B2C. Architecture / Azure / Cloud. Serveurs / Entreprise / Réseaux / IT. Phone / Mobilité.
E N D
Développement natif en C++ Christophe Pichaud – Architecte Sogeti Loïc Joly – Architecte CAST Code / Développement
Design/Général Code/ Dev Office / B2B / LOB / entreprise Mobilité/Consumer/B2C Architecture / Azure / Cloud Serveurs / Entreprise / Réseaux / IT Phone / Mobilité Gaming / Divertissement
Chapitre 1 C++11 Les grands thèmes Développement natif en C++ 11
Pourquoi une session C++ ? • C++11 est comme un nouveau langage • Evolutions du langage – standard C++ 11 • Changer le codage avec des styles/guidances/idioms. • C’est ce qui définit le nouveau langage
Pourquoi le C++ ? • Dans de nombreux domaines, le coût de développement est devenu très faible face au coût d’exploitation
Pourquoi choisir C++ ? “The going word at Facebook is that ‘reasonably written C++ code just runs fast,’ which underscores the enormous effort spent at optimizing PHP and Java code. Paradoxically, C++ code is more difficult to write than in other languages, but efficient code is a lot easier.” – Andrei Alexandrescu
La roadmap C++ • The C++ Standards Commitee • http://www.open-std.org/jtc1/sc22/wg21/ • 2011 : Approbation du standard C++0x • Amélioration de l’implémentation dans « VC++ 11 » • 2008: Draft pour C++0x • Implémentation (partielle) dans Visual C++ 2010 • 2005: TR1= Library Technical Report 1 • Visual C++ 2008 + TR 1 • 2003: TC1 = corrections C++98 • 1998: C++ devient un standard ISO (« C++98 »)
TR1..C++0x.. C++ 11 C++ 0x lambdas r-value reference auto decltype static_assert Thread mutex future<T> vector<vector<int>> variadic templates … TR1 - Technical Report 1 shared_ptr<T> weak_ptr<T> unique_ptr<T> regex tuple array …
C++, mythes et réalités • principes et techniques • gestion des erreurs • pointeurs • Code crado mais je continue sur le même modèle… • Un langage orienté objet compliqué ! • cast • Orienté objet • Compliqué à apprendre ! • Des macros et de goto ! • Peu productif ! • Structure de données compactes et efficaces • Bas niveau ! • Interfaces riches • Template meta-programming • Non sécurisée, dangereux ! • C’est du C ! • Code dur à maintenir • new / delete • Un bon code • le style C++ 11
Evolution du style C++ • Le C++11 permet de faire du code Clean, Safe, Fast. • Clean & Safe : le nouveau style moderne • Fast : l’a toujours été
Aperçu des différences auto type deduction T* shared_ptr<T> new make_shared Then Now return by value + move + auto again to deduce vector<shared_ptr<shape>> circle* p = newcircle( 42 ); vector<shape*> vw;load_shapes( vw ); for( vector<circle*>::iterator i = vw.begin(); i != vw.end(); ++i ) { if( (*i)->weight() > 100 ) cout << **i << “ is a match\n”;} for( vector<circle*>::iterator i = vw.begin();i != vw.end(); ++i ) {delete *i;} delete p; auto p = make_shared<circle>( 42 ); autovw = load_shapes(); for( auto& s : vw ) { if( s->weight() > 100 ) cout << *s << “ is a match\n”;} range-for not exception-safe missing try/catch, __try/__finally Pas de delete. Gestionautomatique du cycle de vie. exception-safe
Gestion de la mémoire • Plus grosse « difficulté du C++ » : la gestion de mémoire • Il n’y a pas de manière unique d’allouer la mémoire en C++ • Heureusement : RAII= Resource Acquisition Is Initialization • Destruction déterministe (i.e. pas besoin de « using ») • Applicable à toutes les ressources « précieuses : • Mémoire • fichiers, sockets, handlesWindows • “C++ is the best language for garbage collection principally because it creates less garbage.”Bjarne Stroustrup
Paroles d’experts ! • Effective C++, Third Edition (2005) by Scott Meyers: • "shared_ptr may be the most widely useful component in TR1." • C++ Coding Standards (2005) by Herb Sutter and Andrei Alexandrescu: • "Store only values and smart pointers in containers. To this we add: If you use [Boost] and [C++TR104] for nothing else, use them for shared_ptr."
Caractéristiquesde shared_ptr<T> • Un template C++ disponibledans <memory> • Basésur le comptage de références • Gain de productivité & robustesseimportants avec impact minimal sur les perfs • Compatible avec les conteneurs STL • Compatible avec le polymorphisme : • shared_ptr<Derived>est convertible en shared_ptr<Base> • Ne casse pas le mécanisme de comptage des références • Besoin de convertir (cast) ? • static_pointer_cast<Derived>(spBase) • dynamic_pointer_cast<Derived>(spBase)
shared_ptr est Non-Intrusif • Possibilitéd’instanciershared_ptr<T> sans modifier T • La gestion des références (uses/weaks) estdans le shared_ptr • Fonctionne avec les types prédéfinis: shared_ptr<int> • S’incorporedans le code sans modifier les types existants • Un même type peutêtremanipuléparfois via un shared_ptr et d’autresfois via d’autresmécanismes
make_shared<T>() • VS 2008 SP1 (VC9 SP1): • shared_ptr<T> sp(new T(args)); • shared_ptr<T> sp(new T(args), del, alloc); • VS 2010 (VC10): • auto sp = make_shared<T>(args); • auto sp = allocate_shared<T>(alloc, args); • Simple et élegant • Écrire le type Tuneseulefois • Robuste • Pas de fuite avec shared_ptr • Efficace • Allocation de mémoiredynamique standard
unique_ptr<T> • Uneseuleréférence de l’objet unique_ptr<Cat> c(new Cat); unique_ptr<Cat> c2(Cat::Load(…)); • Remplaceauto_ptr, qui estobsolète • Compatible avec les collections STL (containers) • Non copiablemaisdéplaçable unique_ptr<Cat> c(new Cat); unique_ptr<Dog> d; d.reset(new Dog); unique_ptr<Monster> m_src(new Monster); unique_ptr<Monster> m_dest(move(m_src));
Containers STL dictionary: map (arbre) ou unordered_map (hash) vector<string> v;v.push_back( “Geddy Lee” ); array<string,50> a; container par défaut: vector compact, efficace, cache, préfetch vecteur de taillle fixe: array compact, efficace, cache, préfetch map<string, string> phone;phone[“Alex Lifeson”] = “+1 (416) 555-1212”; multimap<string, string> phone;phone[“Neil Peart”] = “+1 (416) 555-1212”;phone[“Neil Peart”] = “+1 (905) 555-1234”; unordered_map<string, string> phone;phone[“Alex Lifeson”] = “+1 (416) 555-1212”; unordered_multimap<string, string> phone;phone[“Neil Peart”] = “+1 (416) 555-1212”;phone[“Neil Peart”] = “+1 (905) 555-1234”;
Boucle for avec range • Itération au travers un “range” void f(vector<double>& v) { for (auto x : v) cout << x << '\n'; for (auto& x : v) ++x; // using a reference to allow us to change the value }
nullptr • nullptrexprime un pointeurnul • Cen’est pas un int class Foo { public: Foo(const char *s); Foo(int n); } … Foo f(NULL); Foo f(nullptr);
Syntax Error de template<T> • La problèmed’espaceestrésolu list<vector<string>>lvs;
Uneclasse C++11 type • uneclassepossède par défaut 5 opérations • Un constructeur par copie • Un opérateur de copie • Un constructeur de move • Un opérateur de move • Un destructeur • Conseil • sivousimplémentezune de cesméthodes, alorsimplémentez-les toutes.
enum & enumclassclassenum • Conversion de enumautomatiquement en int et enumfortementtypé enum Alert { green, yellow, election, red }; // traditional enum enum class Color { red, blue }; // scoped and strongly typed enum // no export of enumerator names into enclosing scope // no implicit conversion to int enum class TrafficLight { red, yellow, green }; Alert a = 7; // error (as ever in C++) Color c = 7; // error: no int->Color conversion int a2 = red; // ok: Alert->int conversion int a3 = Alert::red; // error in C++98; ok in C++0x int a4 = blue; // error: blue not in scope int a5 = Color::blue; // error: not Color->int conversion Color a6 = Color::blue; // ok
=default et =delete • Indiquerexplicitement un opérateur de copie par défault class Y { // ... Y& operator=(const Y&) = default; // default copysemantics Y(const Y&) = default; } • Indiquerl’interdiction de la copie class X { // ... X& operator=(const X&) = delete; // Disallow copying X(const X&) = delete; };
constexpr • Le mécanisme de constexpr • Permetd’exprimergénéralement des expressions constantes • Permetd’utiliser les types spécifiques • Fournitl’assurancequel’initialisationestfournie au moment de la compilation • Attention • constexpr ne remplace pas const (et vice versa)
decltype(E) • Le mécanisme de decltype(E) permetd’avoirune expression qui peutêtreutiliséedansunedéclaration • Concept utilisé en programmationgénérique • Appeléeaussi “typeof” • Conseil • Préférezl’utilisation de auto
Initialisation des listes • Maintenant, on peutécrirecela vector<double> v = { 1, 2, 3.456, 99.99 }; list<pair<string,string>> languages = { {"Nygaard","Simula"}, {"Richards","BCPL"}, {"Ritchie","C"} }; map<vector<string>,vector<int>> years = { { {"Maurice","Vincent", "Wilkes"},{1913, 1945, 1951, 1967, 2000} }, { {"Martin", "Ritchards"} {1982, 2003, 2007} }, { {"David", "John", "Wheeler"}, {1927, 1947, 1951, 2004} } }; • L’utilisationde {} est possible via unefonction (souvent par un constructeur) qui accepte un argument std::initializer_list<T> vector (std::initializer_list<E> s) // initializer-list constructor
Délégationde constructeur • Si deuxctor font la même chose, ilfautune routine init() et faire un appeldanschaquector… • Maintenant, ilest possible décrirecela class X { int a; public: X(int x) { if (0<x && x<=max) a=x; else throw bad_X(x); } X() :X{42} { } X(string s) :X{lexical_cast<int>(s)} { } // ... };
Init. de membres de classes • Seules les membresstatiquespeuventêtreinitialisés et avec des expressions constantes… • Maintenant, ilest possible décrirecela class A { public: A() {} A(inta_val) : a(a_val) {} A(D d) : b(g(d)) {} int a = 7; int b = 5; private: HashingFunctionhash_algorithm{"MD5"}; // Cryptographic hash to be applied to all A instances std::string s{"Constructor run"}; // String indicating state in object lifecycle };
long long (64 bits) • Un type long mais qui est very long. • Au moins 64 bits long long x = 9223372036854775807LL;
template typedef • Un typedef pour les templates • Permetuneécriture plus élégante des templates dans le code template<class T> using Vec = std::vector<T,My_alloc<T>>; // standard vector using my allocator Vec<int> fib = { 1, 2, 3, 5, 8, 13 }; // allocates elements using My_alloc • Marche aussi avec le code style-C typedef void (*PFD)(double); // C style using PF = void (*)(double); // using plus C-style type
auto • Avant… • vector<shared_ptr<CPolygon>>::iteratorbeg = polys.begin(); • long et fastidieux à écrire ! • Maintenant, avec « auto » • auto i = polys.begin(); • Type déduit par le compilateur • Equivalent de « var » en C# • Evite aussi certaines conversions implicites en cas d’erreur sur le type
auto map<string, string> m; const regex r("(\\w+) (\\w+)"); for (string s; getline(cin, s); ) { smatch results; if (regex_match(s, results, r)) { m[results[1]] = results[2]; } } for (auto i = m.begin(); i != m.end(); ++i) { cout << i->second << " are " << i->first << endl; } // Au lieu de map<string, string>::iterator
auto: pourquoi l’utiliser ? • autoutilise les règles de détectiond’arguments des templates • const auto * p = foo et const auto& r = barcompilent • auto... • Réduit le code et améliore la lisibilité du code important • Permetd’éviter les erreurs de types, troncations, … • Améliore la généricité du code sans le superflu des expressions intermédiaires • Fonctionnetrèsbien avec les types comme les lambdas
cbegin(), cend(), crbegin(), crend() vector<int> v; for (auto i = v.begin(); i != v.end(); ++i) { // i is vector<int>::iterator } for (auto i = v.cbegin(); i != v.cend(); ++i) { // i is vector<int>::const_iterator }
Références de RValue • Les références de Rvaluepermettentdeux choses importantes : • Déplacement (move semantics) : pour la performance • Perfect forwarding: pour la généricité • = uneseulefonctiongénérique qui accepte des arguments quelconques et les transmet de manièretransparente à uneautrefonction en préservantleur nature (const, lvalue, rvalue, etc) • Ex : make_shared • Les patterns de déplacement et de perfect forwarding sont simples à mettre en oeuvre • Maisilss’appuientsur de nouvellesrèglesd’initialisation, de résolution de surcharge, de déduction des paramètres des templates, etc. • Les conteneurs STL sont “move aware”
Efficacité du déplacement set<widget>load_huge_data() { set<widget> ret; // … load data and populate ret … return ret;} widgets = load_huge_data(); Efficace, pas de copie en profondeur (juste les assignements de pointeurs Efficace: pas de copie en profondeur et pas besoin du contournement allocation dynamique + retour de pointeur Efficace, pas de copiesupplémentaire vector<string> v = IfIHadAMillionStrings(); v.insert( begin(v)+v.size()/2, “tom” );v.insert( begin(v)+v.size()/2, “richard” );v.insert( begin(v)+v.size()/2, “harry” ); HugeMatrixoperator+( const HugeMatrix&, const HugeMatrix&); hm3 = hm1+hm2;
Mécanique du Move / Value Types class my_class {unique_ptr<BigHugeData> data; public:my_class( my_class&& other ) : data( move( other.data ) ) { } my_class& operator=( my_class&& other ) { data = move( other.data ); } ::: void method() {if( !data ) throw “moved-from object”;::: }}; move construction move assignment check (if appropriate) • Copy ? Move: Also enable move if it can be cheaper than a deep copy. • Move / Copy: Some non-value types are naturally move-only. Example: unique_ptr.
Nouveautés des algorithmes • <algorithm> • boolall_of/any_of/none_of(InIt, InIt, Pred) • InItfind_if_not(InIt, InIt, Pred) • OutItcopy_n(InIt, Size, OutIt) • OutItcopy_if(InIt, InIt, OutIt, Pred) • boolis_partitioned(InIt, InIt, Pred) • pair<Out1, Out2> partition_copy(InIt, InIt, Out1, Out2, Pred) • FwdItpartition_point(FwdIt, FwdIt, Pred) • boolis_sorted(FwdIt, FwdIt, Comp?) • FwdItis_sorted_until(FwdIt, FwdIt, Comp?) • boolis_heap(RanIt, RanIt, Comp?) • RanItis_heap_until(RanIt, RanIt, Comp?) • pair<FwdIt, FwdIt> minmax_element(FwdIt, FwdIt, Comp?) • <numeric> • void iota(FwdIt, FwdIt, T) • <iterator> • InIt next(InIt, Distance) • BidItprev(BidIt, Distance)
Algorithmes : trois catégories • Parcours simples • Exemple : for_each = le plus simple • Parcours avec transformations • Exemple : copy = copie tous les éléments répondant à une condition • Tris • Exemples : sort, stable_sort, lower_bound
Parcours simples • All of • Any of • None of • For each • Find • Find end • Find first • Adjacent Find • Count • Mismatch • Equal • Is permutation • Search
Exemple : Find first template<class InputIterator, class Predicate> InputIteratorfind_if(InputIterator first,InputIteratorlast, Predicatepred); • Retourne le premier élémentvérifiant le prédicat • Predicate : • Fonctionsprédéfinies • Classesurchargeant operator() • Lambda
Transformations • Copy • Move • Swap • Transform • Replace • Fill • Generate • Remove • Unique • Reverse • Rotate • Randomshuffle • Partitions
Exemple Transform template<class InputIterator, class OutputIterator, class UnaryOperation> OutputIteratortransform(InputIteratorfirst,InputIteratorlast, OutputIteratorresult, UnaryOperationop); • Exemple: impression de tous les éléments d’un conteneur : copy(points.begin(), points.end(), ostream_iterator<CPoint>(cout, "\n" ));
Tri et assimilés • Sort • Stable_sort • Partial_sort • Nthelement • Binarysearch : lower_bound, upper_bound • Merge
Exemple : sort template<class RandomAccessIterator, class Compare> void sort(RandomAccessIterator first, RandomAccessIteratorlast, Compare comp); • Trie les éléments selon « comp » • Comp = ordre strict (< ou > et non £ ou ³) boolPlusHaut(CPoint &pt1, CPoint &pt2) { return pt1.Y() > pt2.Y(); } sort(points.begin(), points.end(), PlusHaut);
Lambdas • Fonctions simples • pas paramétrables • Classes • Lourdes à écrire • Pb de localité • Lambdas • Le meilleur des deux mondes