C++11 Seminaari Syntaksi part 1 Veli-Pekka Eloranta 13.4. 2012
Yhtenäinen alustussyntaksi vanha C++ string array[]="foo", "bar"; // ok, alustaa listan vector<string> v="foo", "bar"; // syntax error void f(string arg[]) return; f("foo", "bar"); // Syntax error int a = 2; // Sijoitustyylinen alustus int aa[]=2, 3; // sama listalle
Yhtenäinen alustussyntaksi vanha C++ struct Complex int eka; int toka; Complex(int a, int b): eka(a), toka(b) ; Complex z(1,2); // "funktiotyylinen" alustus double x = double(2); // "funktiotyylinen" muunnos/castaus/rakentaminen int abc(1); // Muuttujan määrittely int bcd(); // Funktion esittely int temp=0; int cde(temp); // Muuttujan määrittely vai funktion esittely???
Yhtenäinen alustussyntaksi C++11 Eli C++03:ssa monta erilaista tapaa alustaa tyyppi. Lisäksi kaikki niistä eivät toimi kaikille tyypeille Vain aggregaatti- ja POD-tyypit voidaan alustaa avulla. Ratkaisu C++11:ssa on sallia alustus kaikille tyypeille
Yhtenäinen alustussyntaksi C++11 struct X int x; int y; ; X x1=x1,2; X x2 =1,2; // yhtäsuuruusmerkki optionaalinen X x31,2; X* p=new X1,2; int lukua; int luku2 = a; int* p=newinta; double z=double2; // use as cast, jos toisin päin doublesta => int, //tulee varoitus (narrowing cast)
Yhtenäinen alustussyntaksi C++11 struct tietue1 int x; double y; ; struct tietue2 AltStruct(int x,double y):x_x, y_y private: int x_; double y_; ; Tietue1 muuttuja15, 3.2; // Aggregaatti-alustus,kopioidaan arvo alustuslistasta Tietue2 muuttuja22, 4.3; // Kutsutaan rakentajaa
Yhtenäinen alustussyntaksi C++11 struct IdString std::string name; int identifier; ; IdString get_string() return"foo", 42; //Huomaa eksplisiittisen tyypin puuttuminen //Myös tämä toimii vector<int> foo() return4,32, 42; //Kuten tämäkin toimii void bar(vector<int> arg) //Do stuff bar(1,2,3,4);
Alustuslistat C++11 vector<double> v=1, 2, 3.456, 99.99; // Toimii c++11, //käännösvirhe c++03 Aiemmin ylläoleva alustus tulkittiin taulukkona C++11:ssa -lista hoidetaan funktiolla (usein rakentaja), joka ottaa parametrinaan tyypin std::initializer_list<t> Alustuslista voi olla rajoittamattoman pitkä, mutta alkiot pitää olla sama homogeenisia Standardikirjasto käyttää alustuslistaa, esim string, regex, jne Voidaan käyttää esim. range-for lausekkeessa tai funktion parametrina
Initializer_list esimerkkejä #include <initializer_list> void funktio(initializer_list<int> args) // Do stuff funktio(1,2); funktio(23,345,4567,56789); funktio(1, 2, 3, 1, 100.0); // Narrowing conversion => käännösvirhe // Jos initializer_list <double> tyyppiä funktio(1, 2, 3, 1, 100.0); // ==> On ok funktio(1, 2, 3, 1, 100.0, "humppa"); // ==> Ei humppaa kummallakaan, koska humppaa ei voida castata double:ksi funktio(); // tyhjä lista funktio1,2; // Käännösvirhe: funktiokutsun ( ) puuttuu
Alustuslistat esimerkkejä int a=1; std::complex<double> z1,2; new std::vector<std::string> olipa", kerran", kaukaisessa", maassa"; // 4 string elementtiä funktio( Etunimi", Sukunimi"); // Antaa parametriksi listan, joka sisältää kaksi elementtiä return tuhlaajapoika"; // Palauttaa listan, joka sisältää yhden elementin int* e; // alustus nollaan / null pointeriin x = double1; // eksplisiittisesti rakentaa doublen std::map<std::string,int> anim="bear",4,"cassowary",2,"tiger",7; auto x1 = 1, 2; // decltype(x1) on std::initializer_list<int>
Alustuslistat -esimerkkejä std::vector<std::string> a="ui", "kesäksi", "kuntoon"; for(constauto s: a) std::cout << s << std::endl; for(auto& x:1,3,42,100) std::cout << x << std::endl; // Mitä tulostuu? Miksi?
C++03 - Rakentaja class SomeType int number; public: SomeType(int new_number): number(new_number) SomeType():number(42) ; class SomeType int number; private: void Construct(int new_number) number = new_number; public: SomeType(int new_number) Construct(new_number); SomeType()Construct(42); ; Ei voi kutsua toista rakentajaa
Rakentajan parannukset C++11 class SomeType int number; public: SomeType(int new_number): number(new_number) SomeType():SomeType(42) ;
Poikkeukset exception specification poistuu int Func(); // Voi heittää minkä poikkeuksen vaan int Gunc() throw(); // Ei heitä poikkeuksia, sama kuin nothrow int Hunc()throw(A,B); // Voi heittää vain A:n tai B:n // Kuitenkin... int Huch() throw(a,b) throw C; //.. on ok // Paitsi että aiheuttaa unexpected() -kutsun, joka yleensä kaataa ohjelman Havaittiin, että throw() on kuitenkin hyödyllinen Lisättiin noexcept avainsana, joka kertoo, ettei funktio heitä poikkeusta. Tieto saatavilla käännösaikana ja päättely tehdään silloin. Nopeampaa kuin vanha dynaaminen päättely
Poikkeukset - noexcept Kääntäjä ei välttämättä tunnista kaikkia noexcept määreen rikkomuksia, jos kuitenkin voi päätellä, että funktio saataa heittää poikkeuksen, kääntäjä antaa virheen / varoituksen void funktio () noexcept throw Myexception( paniikki!"); //C++11 käännösvirhe / varoitus // Kuitenkin taas void funktio2 () noexcept std::string n( eihätää!"); // OK, vaikka rakentaja voi heittää // poikkeuksen
Noexcept Noexcept käännösaikainen => kääntäjä voi tehdä optimointeja. Kun havaitaan rike, kutsutaan terminate():a unexpected:n sijasta. (Pinoa ei pureta) noexcept:n yleinen muoto on noexcept(expression). Pelkkänoexcept on lyhenne noexcept (true) :sta. Niinpä onkin mahdollista määrittää funktio ehdollisesti poikkeuksia heittämättömäksi: template<class T> void do_f(vector<t>& v) noexcept(noexcept(f(v.at(0)))); // can throw if f(v.at(0)) can for(int i; i<v.size(); ++i) v.at(i)=f(v.at(i)); noexcept(f(v.at(0))) on tosi jos f(v.at(0)) on noexcept, eli f() ja.at() molemmat ovat noexcept
Noexcept Ei evaluoi operandiaan Purkajan ei pitäisi heittää poikkeusta. Niinpä generoidut purkajat ovat implisiittisesti noexcept tyyppisiä jos luokan kaikki jäsenmuuttujat omaavat noexcept purkajat On huono idea, että siirto operaatio (siirto sijoitusoperaatio ja siirtorakentaja) heittää poikkeuksen. Ninpä noexceptiä tulisi käyttää niissä aina kuin mahdollista. Generoidut kopio ja siirto operaatiot ovat implisiittisesti noexcept tyyppisiä jos kaikkien jäsenmuuttujat omaavat noexcept purkajan. noexcept on laajasti ja systemaattisesti käytössä standardikirjastossa. Pyritty parantamaan suorituskykyä
Noexcept purkajat jotka heittävät poikkeuksen (hyi hyi!) Purkaja on C++11 aina noexcept, vaikka ohjelmoija kirjottaisi: 1 class MyType 2 public: ~MyType() throw Exception(); 3 //... 4 ; Jos purkajasta haluaa heitellä poikkeuksia on kaksi vaihtoehtoa: Lisätä noexcept(false) avainsana purkajaan Periyttää luokka sellaisesta luokasta, joka jo määrittelee purkajansa noexcept(false):ksi Voi tulla yllätyksiä vanhan koodin kanssa: 1 MyType::~MyType() 2 3 LOG( info, "destroying object"); 4
Unicode C++11 tukee UTF-8, UTF-16 ja UTF-32 enkoodauksia char16_t ja char32_t UTF-16 ja UTF-32:lle u8"i'm a UTF-8 string." u"this is a UTF-16 string." // tyyppiä const char16_t[] U"This is a UTF-32 string. // tyyppiä const char32_t[] U Unicode merkin lisääminen: \U2018. // \u 16-bit \U 32-bit Raw string literaalit näitä ei escapeteta R"(The String Data \ Stuff " )" // kaikki sulkujen välissä on stringiä Ja hieno yhdistelmä: u8r"xxx(i'm a "raw UTF-8" string.)xxx" // tässä käytössä delimiter XXX (vaihtoehtoinen ( -erottimelle)
Unicode - ongelmia En keksinyt järkevää tapaa esim. printata unicode stringejä. string UTF-8 vai iso-latin? u16string UTF-16 string u32string UTF-32 string std::string example1 = u8"\u0041\u4061\u10196\u10197"; std::u16string example2 = u"\u0041\u4061\u10196\u10197"; std::u32string example3 = U"WTF-32 string";