C++11 - C++11

C++11 , C++ programlama dili için ISO / IEC 14882 standardının bir versiyonudur . C++11, C++ standardının C++03 adlı önceki sürümünün yerini aldı ve daha sonra C++14 ile değiştirildi . Bu ad, 2010'dan önce yayınlanması beklendiği için daha önce C++0x olarak adlandırılsa da, dil sürümlerini belirtimin yayın yılına göre adlandırma geleneğini takip eder .

Tasarım hedeflerinden biri, çekirdek dilde yapılan değişiklikler yerine kitaplıklardaki değişiklikleri tercih etmek olsa da , C++11 çekirdek dile birkaç ekleme yapar. Temel dilin önemli ölçüde geliştirilmiş alanları, çoklu kullanım desteği, genel programlama desteği, tek tip başlatma ve performansı içerir. Matematiksel özel işlevler kitaplığı dışında, C++ Teknik Rapor 1 (TR1) kitaplıklarının çoğunu içeren C++ Standart Kitaplığı'nda da önemli değişiklikler yapıldı .

C++11, Eylül 2011'de ISO/IEC 14882:2011 olarak yayınlanmıştır ve ücretlidir. Yayınlanan C++11 standardına en çok benzeyen çalışma taslağı, 16 Ocak 2012 tarihli N3337'dir; yalnızca C++11 standardından editoryal düzeltmelere sahiptir.

Tasarım hedefleri

Tasarım komitesi, C++ 11'i tasarlarken bir dizi hedefe bağlı kalmaya çalıştı:

  • İle kararlılık ve uyumluluk muhafaza C ++ 98 ve muhtemelen ile C
  • Çekirdek dili genişletmek yerine standart kitaplık aracılığıyla yeni özellikleri tanıtmayı tercih edin
  • Programlama tekniğini geliştirebilecek değişiklikleri tercih edin
  • Yalnızca belirli uygulamalar için yararlı olan yeni özellikler sunmak yerine, sistemleri ve kitaplık tasarımını kolaylaştırmak için C++'ı geliştirin
  • Daha önceki güvenli olmayan tekniklere daha güvenli alternatifler sağlayarak tip güvenliğini artırın
  • Performansı ve doğrudan donanımla çalışma yeteneğini artırın
  • Gerçek dünya sorunları için uygun çözümler sağlayın
  • Uygulama sıfır genel prensibi (sadece kullanılmalıdır bazı şirketler tarafından ihtiyaç duyulan daha fazla destek programı kullanılır)
  • Uzman programcıların ihtiyaç duyduğu herhangi bir yardımcı programı kaldırmadan C++'ı öğretmeyi ve öğrenmeyi kolaylaştırın

Yeni başlayanlara dikkat edilmesi önemlidir, çünkü çoğu bilgisayar programcısı her zaman böyle olacaktır ve yeni başlayanların çoğu asla bilgilerini genişletmez, kendilerini uzman oldukları dilin bazı yönleriyle çalışmakla sınırlar.

C++ çekirdek dilinin uzantıları

C++ komitesinin bir işlevi, dil çekirdeğinin geliştirilmesidir. Temel dilin önemli ölçüde geliştirilmiş alanları, çoklu kullanım desteği, genel programlama desteği, tek tip başlatma ve performansı içerir.

Çekirdek dil çalışma zamanı performans geliştirmeleri

Bu dil özellikleri, öncelikle, bellek veya hesaplama hızı açısından bir tür performans avantajı sağlamak için mevcuttur.

Referansları değerlendirin ve yapıcıları taşıyın

C++03'te (ve öncesinde), geçicilerin ( genellikle bir ödevin sağ tarafında yer aldığı için " değerler " olarak adlandırılır ) hiçbir zaman değiştirilemez olması amaçlanmıştır - tıpkı C'de olduğu gibi - ve const T&türlerden ayırt edilemez oldukları düşünülürdü ; yine de, bazı durumlarda, geçiciler değiştirilmiş olabilirdi, bu davranış, yararlı bir boşluk olarak bile kabul edildi. C++ 11, sabit olmayan yeni bir başvuru türü ekler.tarafından tanımlanan değer referansıT&& . Bu, "hareket semantiğine" izin vermek amacıyla başlatıldıktan sonra değiştirilmelerine izin verilen geçicilere atıfta bulunur.

C++03 ile ilgili kronik bir performans sorunu, nesneler değere göre iletildiğinde dolaylı olarak meydana gelebilecek maliyetli ve gereksiz derin kopyalardır . Sorunu açıklamak için, std::vector<T>an'ın dahili olarak, tanımlanmış bir boyuta sahip C tarzı bir dizinin etrafındaki bir sarıcı olduğunu düşünün . Bir ederse std::vector<T>geçici oluşturulan veya bir işlevinden döndürülen, sadece yeni oluşturarak saklanabilir std::vector<T>ve içine tüm rvalue verilerini kopyalama. Sonra geçici ve tüm hafızası yok edilir. (Basitlik için bu tartışma, dönüş değeri optimizasyonunu ihmal eder .)

C++11'de bir Hareket yapıcı aitstd::vector<T>olduğu bir bir rvalue referans alırstd::vector<T>yeni içine rvalue dışına iç C tarzı dizi işaretçi kopyalayabilirsinizstd::vector<T>null rvalue içindeki ardından set pointer. Geçici bir daha asla kullanılmayacağından, hiçbir kod boş göstericiye erişmeye çalışmaz ve işaretçi boş olduğundan, kapsam dışına çıktığında belleği silinmez. Bu nedenle, işlem yalnızca derin bir kopya masrafından kurtulmakla kalmaz, aynı zamanda güvenli ve görünmezdir.

Rvalue referansları, standart kitaplığın dışında herhangi bir değişiklik yapmaya gerek kalmadan mevcut koda performans avantajları sağlayabilir. std::vector<T>Geçici bir değer döndüren bir işlevin döndürülen değerinin türünün, std::vector<T> &&geçiciler otomatik olarak değerler olarak kabul edildiğinden, hareket yapıcısını çağırmak için açıkça değiştirilmesi gerekmez . (Ancak, std::vector<T>hareket oluşturucusu olmayan bir C++03 sürümüyse, kopya oluşturucu const std::vector<T>&önemli bir bellek tahsisine neden olacak şekilde bir ile çağrılır .)

Güvenlik nedeniyle bazı kısıtlamalar getirilmiştir. Adlandırılmış bir değişken, böyle bildirilse bile asla bir değer olarak kabul edilmeyecektir. Bir değer elde etmek için fonksiyon şablonu std::move()kullanılmalıdır. Değer referansları da yalnızca belirli koşullar altında değiştirilebilir, öncelikle hareket oluşturucularla kullanılması amaçlanır.

Değer referanslarının ifadesinin doğası ve değer referansları (normal referanslar) için ifadelerde yapılan bazı değişiklikler nedeniyle, değer referansları geliştiricilerin mükemmel fonksiyon iletimi sağlamasına izin verir. Değişken şablonlarla birleştirildiğinde , bu yetenek, argümanları bu belirli argümanları alan başka bir fonksiyona mükemmel bir şekilde iletebilen fonksiyon şablonlarına izin verir. Bu, en çok, bu belirli argümanlar için doğru oluşturucuyu otomatik olarak çağıracak fabrika işlevleri oluşturmak için yapıcı parametrelerini iletmek için kullanışlıdır. Bu, C++ standart kitaplık yöntemlerinin emplace_back kümesinde görülür .

constexpr – Genelleştirilmiş sabit ifadeler

C++ her zaman sabit ifadeler kavramına sahiptir. Bunlar 3+4, derleme zamanında ve çalışma zamanında her zaman aynı sonuçları verecek olan ifadelerdir . Sabit ifadeler derleyiciler için optimizasyon fırsatlarıdır ve derleyiciler bunları derleme zamanında sıklıkla çalıştırır ve sonuçları programa sabit kodlar. Ayrıca, birçok yerde, C++ belirtimi sabit ifadelerin kullanılmasını gerektirir. Bir dizi tanımlamak, sabit bir ifade gerektirir ve numaralandırıcı değerleri sabit ifadeler olmalıdır.

Ancak, sabit bir ifadenin bir işlev çağrısı veya nesne oluşturucu içermesine hiçbir zaman izin verilmemiştir. Yani bu kadar basit bir kod parçası geçersiz:

int get_five() {return 5;}

int some_value[get_five() + 7]; // Create an array of 12 integers. Ill-formed C++

Bu, C++03'te geçerli değildi çünkü get_five() + 7sabit bir ifade değil. Bir C++03 derleyicisinin get_five()çalışma zamanında gerçekten sabit olup olmadığını bilmesinin hiçbir yolu yoktur . Teoride, bu fonksiyon global bir değişkeni etkileyebilir, diğer çalışma zamanı olmayan sabit fonksiyonları çağırabilir, vb.

C++11 constexpr, kullanıcının bir işlev veya nesne oluşturucusunun derleme zamanı sabiti olduğunu garanti etmesini sağlayan anahtar sözcüğünü tanıttı . Yukarıdaki örnek aşağıdaki gibi yeniden yazılabilir:

constexpr int get_five() {return 5;}

int some_value[get_five() + 7]; // Create an array of 12 integers. Valid C++11

Bu, derleyicinin get_five()bir derleme zamanı sabiti olduğunu anlamasını ve doğrulamasını sağlar .

constexprBir fonksiyonda kullanmak , o fonksiyonun yapabileceklerine bazı sınırlamalar getirir. İlk olarak, işlevin geçersiz olmayan bir dönüş tipi olması gerekir. İkincisi, işlev gövdesi değişkenleri bildiremez veya yeni türler tanımlayamaz. Üçüncüsü, gövde yalnızca bildirimler, boş ifadeler ve tek bir dönüş ifadesi içerebilir. Argüman değiştirildikten sonra, return ifadesindeki ifadenin sabit bir ifade üreteceği şekilde argüman değerleri bulunmalıdır.

C++ 11'den önce, değişkenlerin değerleri yalnızca değişkenler const bildirilmişse, sabit bir ifade olan bir başlatıcıya sahipse ve integral veya numaralandırma türündeyse sabit ifadelerde kullanılabilir. C++11, constexpranahtar kelimeyle tanımlanmışsa değişkenlerin integral veya numaralandırma türünde olması gerektiği kısıtlamasını kaldırır :

constexpr double earth_gravitational_acceleration = 9.8;
constexpr double moon_gravitational_acceleration = earth_gravitational_acceleration / 6.0;

Bu tür veri değişkenleri dolaylı olarak const'tır ve sabit bir ifade olması gereken bir başlatıcıya sahip olmalıdır.

Kullanıcı tanımlı türlerden sabit ifade veri değerleri oluşturmak için, yapıcılar ile de bildirilebilir constexpr. Bir constexpryapıcının işlev gövdesi yalnızca bildirimler ve boş ifadeler içerebilir ve bir constexprişlevde olduğu gibi değişkenleri bildiremez veya türleri tanımlayamaz . Argüman ikamesinden sonra, sınıfın üyelerini sabit ifadelerle başlatacak şekilde argüman değerleri olmalıdır. Bu türler için yıkıcılar önemsiz olmalıdır.

Herhangi bir yapıcıya sahip bir türün kopya yapıcısı, türdeki nesnelerin bir constexpr işlevinden değerle döndürülmesine izin vermek için constexprgenellikle bir constexpryapıcı olarak da tanımlanmalıdır . Bir sınıfın kopya oluşturucular, işleç aşırı yüklemeleri vb. gibi herhangi bir üye işlevi, constexprconstexpr işlevlerinin gereksinimlerini karşıladıkları sürece olarak bildirilebilir . Bu, derleyicinin nesneleri derleme zamanında kopyalamasına, üzerlerinde işlemler gerçekleştirmesine vb.

Bir constexpr işlevi veya yapıcısı, sabit ifadeler olmayan bağımsız değişkenlerle çağrılırsa, çağrı, işlev constexpr değilmiş gibi davranır ve elde edilen değer sabit bir ifade değildir. Benzer şekilde, bir constexpr işlevinin return ifadesindeki ifade, belirli bir çağrı için sabit bir ifade olarak değerlendirilmiyorsa, sonuç sabit bir ifade değildir.

constexprC++20'deconsteval tanıtılan ' dan farklıdır, çünkü ikincisi her zaman bir derleme zaman sabiti üretmelidir, ancak bu kısıtlamaya sahip değildir. constexpr

Düz eski verilerin tanımında değişiklik

C++03'te, bir sınıf veya yapının düz eski veri (POD) türü olarak kabul edilmesi için bir dizi kuralı izlemesi gerekir . Bu tanıma uyan türler, C ile uyumlu nesne düzenleri üretir ve bunlar statik olarak da başlatılabilir. C++03 standardında, bir derleyicinin programı kabul edememesi için hiçbir teknik neden olmamasına rağmen, hangi türlerin C ile uyumlu olduğu veya statik olarak başlatılabileceği konusunda kısıtlamalar vardır; birisi bir C++03 POD türü oluşturup sanal olmayan bir üye işlevi ekleseydi, bu tür artık bir POD türü olmaz, statik olarak başlatılamaz ve bellek düzeninde herhangi bir değişiklik olmamasına rağmen C ile uyumsuz olurdu .

C++11, POD konseptini iki ayrı konsepte bölerek birkaç POD kurallarını gevşetti: önemsiz ve standart düzen .

Önemsiz bir tür statik olarak başlatılabilir. Bu aynı zamanda memcpy, bir kopya oluşturucu kullanmak yerine verileri aracılığıyla çevresinde kopyalamanın geçerli olduğu anlamına gelir . Önemsiz bir türün ömrü, bir kurucu tamamlandığında değil, depolaması tanımlandığında başlar.

Önemsiz bir sınıf veya yapı şu şekilde tanımlanır:

  1. Önemsiz bir varsayılan kurucuya sahiptir. Bu, varsayılan yapıcı sözdizimini ( SomeConstructor() = default;) kullanabilir.
  2. Varsayılan sözdizimini kullanabilen önemsiz kopyala ve taşı yapıcıları vardır.
  3. Varsayılan sözdizimini kullanabilen önemsiz kopyalama ve taşıma atama operatörlerine sahiptir.
  4. Sanal olmaması gereken önemsiz bir yıkıcıya sahiptir.

Yapıcılar, yalnızca sınıfın sanal üye işlevleri ve sanal temel sınıflar yoksa önemsizdir. Kopyalama/taşıma işlemleri ayrıca tüm statik olmayan veri üyelerinin önemsiz olmasını gerektirir.

Standart düzen olan bir tür , üyelerini C ile uyumlu bir şekilde sipariş ettiği ve paketlediği anlamına gelir. Bir sınıf veya yapı, tanım gereği standart düzendir, aşağıdakiler sağlanır:

  1. Sanal işlevi yoktur
  2. Sanal temel sınıfları yoktur
  3. Statik olmayan tüm veri üyeleri aynı erişim kontrolüne sahiptir (genel, özel, korumalı)
  4. Temel sınıflarındakiler de dahil olmak üzere tüm statik olmayan veri üyeleri, hiyerarşide aynı sınıftadır.
  5. Yukarıdaki kurallar tüm temel sınıflar ve sınıf hiyerarşisindeki tüm statik olmayan veri üyeleri için de geçerlidir.
  6. İlk tanımlanan statik olmayan veri üyesiyle aynı türde hiçbir temel sınıfa sahip değildir.

Bir sınıf/yapı/birlik, önemsizse, standart düzendeyse ve tüm statik olmayan veri üyeleri ve temel sınıfları POD ise, POD olarak kabul edilir.

Bu kavramları ayırarak birinden vazgeçmeden diğerinden vazgeçmek mümkün hale gelir. Karmaşık hareket ve kopya oluşturuculara sahip bir sınıf önemsiz olmayabilir, ancak standart düzen olabilir ve bu nedenle C ile birlikte çalışabilir. Benzer şekilde, genel ve özel statik olmayan veri üyelerine sahip bir sınıf standart düzen olmaz, ancak olabilir önemsiz ve böylece memcpy-mümkün.

Çekirdek dil oluşturma süresi performans geliştirmeleri

Dış şablon

C++03'te, bir çeviri biriminde tam olarak belirtilen bir şablonla karşılaşıldığında, derleyici bir şablonu örneklemelidir. Şablon birçok çeviri biriminde aynı türlerle somutlaştırılırsa, bu derleme sürelerini önemli ölçüde artırabilir. Bunu C++03'te engellemenin bir yolu yoktur, bu nedenle C++11, harici veri bildirimlerine benzer şekilde harici şablon bildirimlerini tanıttı.

C++03, derleyiciyi bir şablonu başlatmaya zorlamak için bu sözdizimine sahiptir:

template class std::vector<MyClass>;

C++ 11 şimdi bu sözdizimini sağlıyor:

extern template class std::vector<MyClass>;

hangi derleyici söyler değil bu çeviri biriminde şablonu örneğini.

Temel dil kullanılabilirliği geliştirmeleri

Bu özellikler, dilin kullanımını kolaylaştırmak için birincil amaç için mevcuttur. Bunlar, tür güvenliğini iyileştirebilir, kod tekrarını en aza indirebilir, hatalı kodu daha az olası hale getirebilir, vb.

Başlatıcı listeleri

C++03, başlatıcı-liste özelliğini C'den devralmıştır. Bir yapı veya diziye, yapıdaki üyelerin tanımlarının sırasına göre kaşlı ayraçlar içinde bir argüman listesi verilir. Bu başlatıcı listeleri özyinelemelidir, bu nedenle diğer yapıları içeren bir dizi yapı veya yapı bunları kullanabilir.

struct Object
{
    float first;
    int second;
};

Object scalar = {0.43f, 10}; //One Object, with first=0.43f and second=10
Object anArray[] = {{13.4f, 3}, {43.28f, 29}, {5.934f, 17}}; //An array of three Objects

Bu, statik listeler veya bir yapıyı bir değere başlatmak için çok kullanışlıdır. C++ ayrıca bir nesneyi başlatmak için yapıcılar sağlar, ancak bunlar genellikle başlatıcı listesi kadar kullanışlı değildir. Ancak, C++03 yalnızca Düz Eski Veri (POD) tanımına uyan yapılar ve sınıflarda başlatıcı listelerine izin verir; C++ 11, başlatıcı listelerini genişletir, böylece standart kapsayıcılar dahil olmak üzere tüm sınıflar için kullanılabilirler std::vector.

C++11, kavramı, adı verilen bir şablona bağlar std::initializer_list. Bu, yapıcıların ve diğer işlevlerin başlatıcı listelerini parametre olarak almasına izin verir. Örneğin:

class SequenceClass
{
public:
    SequenceClass(std::initializer_list<int> list);
};

Bu, SequenceClassaşağıdakiler gibi bir tamsayı dizisinden oluşturulmasına izin verir :

SequenceClass some_var = {1, 4, 5, 6};

Bu kurucu, başlatıcı-liste-yapıcısı olarak adlandırılan özel bir kurucu türüdür. Böyle bir kurucuya sahip sınıflar, tek tip başlatma sırasında özel olarak ele alınır (aşağıya bakın )

Şablon sınıfı std::initializer_list<>, birinci sınıf bir C++11 standart kitaplık türüdür. Bunlar, C++ 11 derleyicisi tarafından, {}bu tür parantezlerin bir olarak çıkarılacağı bağlamlarda bir tür adı olmadan sözdizimi kullanılarak std::initializer_listveya benzeri türü açıkça belirterek std::initializer_list<SomeType>{args}(ve diğer inşaat sözdizimi türleri için böyle devam eder) statik olarak oluşturulabilir .

Liste oluşturulduktan sonra kopyalanabilir, bu ucuzdur ve referans bazında bir kopya işlevi görecektir (sınıf tipik olarak bir çift başlangıç/bitiş işaretçisi olarak uygulanır). An std::initializer_listsabittir: üyeleri oluşturulduktan sonra değiştirilemez ve bu üyelerdeki veriler değiştirilemez (bu, onlardan taşınmayı, sınıf üyelerine kopyalar gerektirmeyi vb. hariç tutar).

Yapısı derleyici tarafından özel olarak ele alınsa da an std::initializer_listgerçek bir türdür ve bu nedenle sınıf kurucularının yanı sıra başka yerlerde de kullanılabilir. Normal işlevler, yazılan s'leri std::initializer_listbağımsız değişken olarak alabilir . Örneğin:

void function_name(std::initializer_list<float> list); // Copying is cheap; see above

function_name({1.0f, -3.45f, -0.4f});

Bunun standart kitaplıktaki örnekleri, sayısal türde s alan std::min()ve std::max()şablonlarını std::initializer_listiçerir.

Standart kapsayıcılar ayrıca şu yollarla da başlatılabilir:

std::vector<std::string> v = { "xyzzy", "plugh", "abracadabra" };
std::vector<std::string> v({ "xyzzy", "plugh", "abracadabra" });
std::vector<std::string> v{ "xyzzy", "plugh", "abracadabra" }; // see "Uniform initialization" below

Tek tip başlatma

C++03'ün türlerin başlatılmasıyla ilgili bir takım sorunları vardır. Bunu yapmanın birkaç yolu vardır ve bazıları değiştirildiğinde farklı sonuçlar verir. Örneğin, geleneksel kurucu sözdizimi bir işlev bildirimi gibi görünebilir ve derleyicinin en can sıkıcı ayrıştırma kuralının onu böyle bir hata yapmamasını sağlamak için adımlar atılmalıdır . Yalnızca toplamalar ve POD türleri, toplama başlatıcılarıyla ( kullanılarak SomeType var = {/*stuff*/};) başlatılabilir .

C++11, herhangi bir nesne üzerinde çalışan tamamen tek tip tip başlatmaya izin veren bir sözdizimi sağlar. Başlatıcı listesi sözdiziminde genişler:

struct BasicStruct
{
    int x;
    double y;
};

struct AltStruct
{
    AltStruct(int x, double y)
        : x_{x}
        , y_{y}
    {}

private:
    int x_;
    double y_;
};

BasicStruct var1{5, 3.2};
AltStruct var2{2, 4.3};

Başlatma, var1tam olarak toplu başlatma gibi davranır. Yani, bir nesnenin her bir veri üyesi, sırayla, başlatıcı listesinden karşılık gelen değerle kopyalanarak başlatılacaktır. Gerektiğinde örtük tür dönüştürme kullanılacaktır. Dönüştürme yoksa veya yalnızca daraltma dönüştürmesi varsa, program hatalı biçimlendirilmiştir. Başlatma, var2yapıcıyı çağırır.

Bir de şunu yapabilir:

struct IdString
{
    std::string name;
    int identifier;
};

IdString get_string()
{
    return {"foo", 42}; //Note the lack of explicit type.
}

Tekdüze başlatma, zaman zaman hala gerekli olan yapıcı sözdiziminin yerini almaz. Bir sınıfın bir başlatıcı listesi oluşturucusu ( TypeName(initializer_list<SomeType>);) varsa, başlatıcı listesinin sıra oluşturucunun türüne uyması koşuluyla diğer oluşturma biçimlerine göre önceliği alır. C++ 11 sürümü std::vector, şablon türü için bir başlatıcı listesi oluşturucusuna sahiptir. Böylece bu kod:

std::vector<int> the_vec{4};

başlatıcı listesi yapıcısını çağırır, bunun yapıcısı std::vectortek bir boyut parametresi almaz ve bu boyutta vektörü oluşturur. İkinci kurucuya erişmek için kullanıcının doğrudan standart kurucu sözdizimini kullanması gerekir.

Tür çıkarımı

C++03'te (ve C) bir değişken kullanmak için türü açıkça belirtilmelidir. Bununla birlikte, şablon türlerinin ve şablon metaprogramlama tekniklerinin ortaya çıkmasıyla, bir şeyin türü, özellikle bir işlevin iyi tanımlanmış dönüş değeri kolayca ifade edilemeyebilir. Bu nedenle, ara maddeleri değişkenlerde depolamak zordur, muhtemelen belirli bir metaprogramlama kitaplığının dahili bilgilerine ihtiyaç duyulur.

C++ 11, bunun iki şekilde hafifletilmesine izin verir. İlk olarak, açık bir başlatma ile bir değişkenin tanımı autoanahtar kelimeyi kullanabilir . Bu, başlatıcının belirli türünde bir değişken oluşturur:

auto some_strange_callable_type = std::bind(&some_function, _2, _1, some_object);
auto other_variable = 5;

türü some_strange_callable_type, basitçe, belirli şablon işlevinin std::bindbu belirli argümanlar için dönüşleri geçersiz kıldığı şeydir. Bu tür, semantik analiz görevlerinin bir parçası olarak derleyici tarafından prosedürel olarak kolayca belirlenir, ancak kullanıcının inceleme sırasında belirlemesi kolay değildir. Türü other_variablede iyi tanımlanmıştır, ancak kullanıcının belirlemesi daha kolaydır. Bir olan inttam sayı sabit değer olarak aynı tipte olan,.

Anahtar sözcüğün autoC++'daki bu kullanımı, türlenmemiş bir otomatik değişken tanımını belirtmekle ilgili bir rolde başlangıçta türsüz öncül dil B'de kullanılan bu anahtar sözcüğün anlamını yeniden amaçlar .

Ayrıca, anahtar kelime decltype, derleme zamanında ifadenin türünü belirlemek için kullanılabilir. Örneğin:

int some_int;
decltype(some_int) other_integer_variable = 5;

Bu, ile bağlantılı olarak daha kullanışlıdır auto, çünkü auto değişkenin türü yalnızca derleyici tarafından bilinir. Bununla birlikte, operatör aşırı yüklemesini ve özel türleri decltypeyoğun olarak kullanan koddaki ifadeler için de çok yararlı olabilir .

autokodun ayrıntı düzeyini azaltmak için de kullanışlıdır. Örneğin, yazmak yerine

for (std::vector<int>::const_iterator itr = myvec.cbegin(); itr != myvec.cend(); ++itr)

programcı daha kısa olanı kullanabilir

for (auto itr = myvec.cbegin(); itr != myvec.cend(); ++itr)

"myvec" başlangıç/bitiş yineleyicilerini uyguladığı için daha da sıkıştırılabilir:

for (const auto& x : myvec)

Bu fark, programcı kapları yerleştirmeye başladığında büyür, ancak bu gibi durumlarda typedefs, kod miktarını azaltmanın iyi bir yoludur.

ile gösterilen decltypetür, tarafından çıkarılan türden farklı olabilir auto.

#include <vector>
int main()
{
    const std::vector<int> v(1);
    auto a = v[0];        // a has type int
    decltype(v[0]) b = 1; // b has type const int&, the return type of
                          //   std::vector<int>::operator[](size_type) const
    auto c = 0;           // c has type int
    auto d = c;           // d has type int
    decltype(c) e;        // e has type int, the type of the entity named by c
    decltype((c)) f = c;  // f has type int&, because (c) is an lvalue
    decltype(0) g;        // g has type int, because 0 is an rvalue
}

Menzil tabanlı for döngüsü

C++11, forbir dizi öğe üzerinde kolay yinelemeye izin vermek için ifadenin sözdizimini genişletir :

int my_array[5] = {1, 2, 3, 4, 5};
// double the value of each element in my_array:
for (int& x : my_array)
    x *= 2;

// similar but also using type inference for array elements
for (auto& x : my_array)
    x *= 2;

for"Aralık tabanlı" olarak adlandırılan bu form , listedeki her öğe üzerinde yinelenir. C tarzı diziler, başlatıcı listeleri ve kendisi için tanımlanmış begin()ve end()yineleyiciler döndüren işlevlere sahip herhangi bir tür için çalışacaktır. Başlangıç/bitiş çiftlerine sahip tüm standart kitaplık kapları, aralık tabanlı for ifadesi ile çalışacaktır.

Lambda işlevleri ve ifadeleri

C++11, lambda işlevleri adı verilen anonim işlevler oluşturma yeteneği sağlar . Bunlar aşağıdaki gibi tanımlanır:

[](int x, int y) -> int { return x + y; }

Dönüş türü ( -> intbu örnekte), tüm returnifadeler aynı türü döndürdüğü sürece atlanabilir . Bir lambda isteğe bağlı olarak bir kapatma olabilir .

Alternatif işlev sözdizimi

Standart C işlev bildirim sözdizimi, C dilinin özellik kümesi için tamamen yeterliydi. C++, C'den evrimleştiğinden, temel sözdizimini korudu ve gerektiğinde genişletti. Bununla birlikte, C++ daha karmaşık hale geldikçe, özellikle şablon işlevi bildirimleriyle ilgili olarak çeşitli sınırlamalar ortaya çıkardı. Örneğin, C++03'te buna izin verilmez:

template<class Lhs, class Rhs>
  Ret adding_func(const Lhs &lhs, const Rhs &rhs) {return lhs + rhs;} //Ret must be the type of lhs+rhs

Tip Ret, türlerin eklenmesi Lhsve Rhsüreteceği şeydir. Yukarıda belirtilen C++11 işleviyle bile decltypebu mümkün değildir:

template<class Lhs, class Rhs>
  decltype(lhs+rhs) adding_func(const Lhs &lhs, const Rhs &rhs) {return lhs + rhs;} //Not valid C++11

Bunun nedeni ++ C geçerli değil lhsve rhshenüz tanımlanmamış; ayrıştırıcı işlev prototipinin geri kalanını ayrıştırana kadar bunlar geçerli tanımlayıcılar olmayacaklardır.

Bu soruna geçici bir çözüm bulmak için, C++ 11, takip eden bir dönüş tipi ile yeni bir işlev bildirimi sözdizimi sundu :

template<class Lhs, class Rhs>
  auto adding_func(const Lhs &lhs, const Rhs &rhs) -> decltype(lhs+rhs) {return lhs + rhs;}

Bu sözdizimi, daha sıradan işlev bildirimleri ve tanımları için kullanılabilir:

struct SomeStruct
{
    auto func_name(int x, int y) -> int;
};

auto SomeStruct::func_name(int x, int y) -> int
{
    return x + y;
}

Bu durumda "auto" anahtar sözcüğünün kullanımı, sözdiziminin yalnızca bir parçasıdır ve C++ 11'de otomatik tür kesintisi gerçekleştirmez. Ancak, C++14 ile başlayarak, sondaki dönüş türü tamamen kaldırılabilir ve derleyici dönüş türünü otomatik olarak çıkaracaktır.

Nesne yapım iyileştirmesi

C++03'te, bir sınıfın kurucularının, o sınıfın bir başlatıcı listesindeki diğer kurucuları çağırmasına izin verilmez. Her kurucu, tüm sınıf üyelerini kendisi oluşturmalı veya aşağıdaki gibi ortak bir üye işlevi çağırmalıdır:

class SomeType
{
public:
    SomeType(int new_number)
    {
        Construct(new_number);
    }

    SomeType()
    {
        Construct(42);
    }

private:
    void Construct(int new_number)
    {
        number = new_number;
    }

    int number;
};

Temel sınıfların oluşturucuları, doğrudan türetilmiş sınıflara maruz bırakılamaz; bir temel sınıf oluşturucu uygun olsa bile, türetilmiş her sınıf, yapıcıları uygulamalıdır. Sınıfların sabit olmayan veri üyeleri, bu üyelerin bildirildiği sitede başlatılamaz. Yalnızca bir kurucuda başlatılabilirler.

C++ 11, tüm bu sorunlara çözümler sunar.

C++11, yapıcıların diğer eş yapıcıları ( delegasyon olarak adlandırılır ) çağırmasına izin verir . Bu, yapıcıların başka bir yapıcının davranışını minimum ek kodla kullanmalarına olanak tanır. Delegasyon, Java ve Objective-C gibi diğer dillerde kullanılmıştır .

Bu sözdizimi aşağıdaki gibidir:

class SomeType
{
    int number;

public:
    SomeType(int new_number) : number(new_number) {}
    SomeType() : SomeType(42) {}
};

Bu durumda, new_numbervarsayılan bir parametre yapılarak aynı etkinin elde edilebileceğine dikkat edin . Bununla birlikte, yeni sözdizimi, varsayılan değerin (42) arayüzden ziyade uygulamada ifade edilmesine izin verir - işlev parametrelerinin varsayılan değerleri çağrı sitelerine "pişirildiğinden" kitaplık kodunun koruyucuları için bir avantajdır, oysa yapıcı yetkilendirme izin verir kütüphane kullanılarak kodun yeniden derlenmesine gerek kalmadan değiştirilecek değer.

Bu bir uyarı ile birlikte gelir: C++03, yapıcısı yürütmeyi bitirdiğinde oluşturulacak bir nesneyi dikkate alır, ancak C++11, herhangi bir yapıcı yürütmeyi bitirdiğinde oluşturulmuş bir nesneyi dikkate alır . Birden çok kurucunun yürütmesine izin verileceğinden, bu, her temsilci kurucunun kendi türünde tam olarak oluşturulmuş bir nesne üzerinde yürütüleceği anlamına gelir. Türetilmiş sınıf oluşturucuları, temel sınıflarındaki tüm yetkilendirme tamamlandıktan sonra yürütülür.

Temel sınıf oluşturucular için C++11, bir sınıfın temel sınıf oluşturucularının devralınacağını belirtmesine izin verir. Böylece, C++11 derleyicisi, türetilmiş sınıfın temel sınıfa kalıtımını ve iletilmesini gerçekleştirmek için kod üretecektir. Bu ya hep ya hiç özelliğidir: ya bu temel sınıfın tüm kurucuları iletilir ya da hiçbiri yönlendirilmez. Ayrıca, türetilmiş sınıfın bir yapıcısının imzasıyla eşleşirse ve birden çok kalıtım için kısıtlamalar varsa, devralınan bir kurucu gölgelenir : sınıf kurucuları , aynı imzaya sahip kurucuları kullanan iki sınıftan miras alınamaz .

Sözdizimi aşağıdaki gibidir:

class BaseClass
{
public:
    BaseClass(int value);
};

class DerivedClass : public BaseClass
{
public:
    using BaseClass::BaseClass;
};

Üye başlatma için C++ 11 bu sözdizimine izin verir:

class SomeClass
{
public:
    SomeClass() {}
    explicit SomeClass(int new_value) : value(new_value) {}

private:
    int value = 5;
};

Yapıcı valuebaşlatmayı kendi başına geçersiz kılmazsa, sınıfın herhangi bir yapıcısı 5 ile başlatılacaktır. Bu nedenle, yukarıdaki boş kurucu value, sınıf tanımının belirttiği gibi başlatılacaktır , ancak bir int alan kurucu, onu verilen parametreye başlatacaktır.

Ayrıca, yukarıda gösterilen atama başlatma yerine yapıcı veya tek tip başlatma kullanabilir.

Açık geçersiz kılmalar ve son

C++03'te, bir temel sınıf işlevini geçersiz kılmak istendiğinde yanlışlıkla yeni bir sanal işlev oluşturmak mümkündür. Örneğin:

struct Base
{
    virtual void some_func(float);
};

struct Derived : Base
{
    virtual void some_func(int);
};

Derived::some_funcTemel sınıf sürümünün yerini alması amaçlandığını varsayalım . Ancak bunun yerine, farklı bir imzaya sahip olduğu için ikinci bir sanal işlev oluşturur. Bu, özellikle bir kullanıcı temel sınıfı değiştirmeye gittiğinde yaygın bir sorundur.

C++11, bu sorunu çözmek için sözdizimi sağlar.

struct Base
{
    virtual void some_func(float);
};

struct Derived : Base
{
    virtual void some_func(int) override; // ill-formed - doesn't override a base class method
};

overrideTam bu imza ile sanal işlevi varsa derleyici temel sınıf (lar) kontrol edecek özel tanımlayıcı araçları görmek için. Ve yoksa, derleyici bir hata gösterecektir.

C++11 ayrıca, sınıflardan devralmayı önleme veya türetilmiş sınıflarda yöntemleri geçersiz kılmayı önleme özelliğini de ekler. Bu özel tanımlayıcı ile yapılır final. Örneğin:

struct Base1 final { };

struct Derived1 : Base1 { }; // ill-formed because the class Base1 has been marked final
struct Base2
{
    virtual void f() final;
};

struct Derived2 : Base2
{
    void f(); // ill-formed because the virtual function Base2::f has been marked final
};

Bu örnekte, virtual void f() final;ifade yeni bir sanal işlev bildirir, ancak türetilmiş sınıfların onu geçersiz kılmasını da önler. Ayrıca, türetilmiş sınıfların bu belirli işlev adını ve parametre kombinasyonunu kullanmasını önleme etkisine de sahiptir.

Ne dil ne overridede finalanahtar kelimeler olduğuna dikkat edin . Bildirici nitelikleri için teknik olarak tanımlayıcılardır:

  • yalnızca bu belirli sondaki bağlamlarda (tüm tür belirteçleri, erişim belirteçleri, üye bildirimleri (yapı, sınıf ve numaralandırma türleri için) ve bildirici belirteçlerinden sonra, ancak her bildiricinin virgül içinde başlatılmasından veya kod uygulamasından önce kullanıldığında öznitelik olarak özel anlam kazanırlar. - deklaratörlerin ayrılmış listesi);
  • bildirilen tür imzasını değiştirmezler ve herhangi bir kapsamda herhangi bir yeni tanımlayıcı bildirmez veya geçersiz kılmazlar;
  • tanınan ve kabul edilen bildirici öznitelikleri, C++'ın gelecekteki sürümlerinde genişletilebilir (derleyiciye özel bazı uzantılar, derleyiciye kod oluşturma seçenekleri veya optimizasyon ipuçları sağlamak veya derlenmiş koda ek veriler oluşturmak için ek bildirim özniteliklerini zaten tanır. hata ayıklayıcılar, bağlayıcılar ve derlenmiş kodun konuşlandırılması veya sisteme özgü ek güvenlik öznitelikleri sağlamak veya çalışma zamanında yansıtma yeteneklerini geliştirmek veya diğer programlama dilleri ve çalıştırma zamanı sistemleri ile birlikte çalışabilirlik için ek bağlayıcı bilgiler sağlamak; bu uzantılar parametreler alabilir bildirici öznitelik tanımlayıcısından sonra parantezler arasında; ANSI uyumluluğu için, bu derleyiciye özgü uzantılar çift alt çizgi önek kuralını kullanmalıdır).
  • Başka herhangi bir yerde, yeni bildirimler için geçerli tanımlayıcılar olabilirler (ve daha sonra erişilebilirlerse kullanılabilirler).

Boş işaretçi sabiti

Yalnızca bu bölümün ve yalnızca bu bölümün amaçları doğrultusunda, “ 0” öğesinin her oluşumu, “ olarak değerlendirilen 0, int türünden bir sabit ifade” anlamına gelir . Gerçekte, sabit ifadesi herhangi bir integral türünde olabilir.

1972'de C'nin başlangıcından bu yana, sabit 0, sabit tamsayı ve boş gösterici sabitinin ikili rolüne sahipti. Çift anlamının doğasında var olan belirsizlik 0, C'de NULL, genellikle ya ((void*)0)veya şeklinde genişleyen önişlemci makrosu kullanılarak ele alındı 0. C ++ yasakladığı örtük dönüşüm void *diğer işaretçi türlerine, böylece döküm yararını kaldırılması 0için void *. Sonuç olarak, yalnızca 0boş gösterici sabiti olarak izin verilir. Bu, işlev aşırı yüklemesiyle kötü etkileşime girer :

void foo(char *);
void foo(int);

Eğer NULLolarak tanımlanır 0(C ++ çoğu böyledir), deyim foo(NULL);arayacak foo(int)programcı amaçlanan şey neredeyse kesin değildir ve olmayan bir kod yüzeysel okuma önerdiklerini, hangi.

C++11, ayırt edici bir boş gösterici sabiti olarak hizmet edecek yeni bir anahtar sözcük sunarak bunu düzeltir: nullptr. Bu, nullptr_törtük olarak dönüştürülebilir ve herhangi bir işaretçi türü veya işaretçiden üyeye türüyle karşılaştırılabilir olan türündedir. dışında, dolaylı olarak dönüştürülebilir veya integral türlerle karşılaştırılabilir değildir bool. Orijinal teklif, bir tür nullptr_tdeğerinin dönüştürülememesi gerektiğini belirtirken bool, çekirdek dil çalışma grubu, normal işaretçi türleriyle tutarlılık için böyle bir dönüşümün isteneceğine karar verdi. Önerilen metin değişiklikleri Haziran 2008'de oybirliğiyle Çalışma Belgesi'ne oylandı. Benzer bir öneri C standardı çalışma grubuna da getirildi.

Geriye dönük uyumluluk nedenleriyle, 0geçerli bir boş gösterici sabiti olarak kalır.

char *pc = nullptr;     // OK
int  *pi = nullptr;     // OK
bool   b = nullptr;     // OK. b is false.
int    i = nullptr;     // error

foo(nullptr);           // calls foo(nullptr_t), not foo(int);
/*
  Note that foo(nullptr_t) will actually call foo(char *) in the example above using an implicit conversion,
  only if no other functions are overloading with compatible pointer types in scope.
  If multiple overloadings exist, the resolution will fail as it is ambiguous,
  unless there is an explicit declaration of foo(nullptr_t).

  In standard types headers for C++11, the nullptr_t  type should be declared as:
      typedef decltype(nullptr) nullptr_t;
  but not as:
      typedef int nullptr_t; // prior versions of C++ which need NULL to be defined as 0
      typedef void *nullptr_t; // ANSI C which defines NULL as ((void*)0)
*/

Kesinlikle yazılan numaralandırmalar

C++03'te numaralandırmalar tür açısından güvenli değildir. Numaralandırma türleri farklı olsa bile, bunlar etkili bir şekilde tam sayılardır. Bu, farklı numaralandırma türlerinin iki numaralandırma değeri arasında karşılaştırmaya izin verir. C++03'ün sağladığı tek güvenlik, bir enum türündeki bir tamsayı veya değerin örtük olarak başka bir enum türüne dönüşmemesidir. Ayrıca, temel alınan integral türü uygulama tarafından tanımlanır; Numaralandırmanın boyutuna bağlı olan kod bu nedenle taşınabilir değildir. Son olarak, numaralandırma değerleri, çevreleyen kapsama göre kapsamlandırılır. Bu nedenle, aynı kapsamdaki iki ayrı numaralandırmanın eşleşen üye adlarına sahip olması mümkün değildir.

C++11, bu sorunlardan hiçbirine sahip olmayan özel bir numaralandırma sınıflandırmasına izin verir. Bu, enum class( enum structeşanlamlı olarak da kabul edilir) bildirimi kullanılarak ifade edilir:

enum class Enumeration
{
    Val1,
    Val2,
    Val3 = 100,
    Val4 // = 101
};

Bu numaralandırma tür açısından güvenlidir. Enum sınıfı değerleri örtük olarak tamsayılara dönüştürülmez. Bu nedenle, tam sayılarla da karşılaştırılamazlar (ifade Enumeration::Val4 == 101derleme hatası verir).

Altta yatan enum sınıfları türü her zaman bilinir. Varsayılan tür int; bu, bu örnekte görülebileceği gibi farklı bir integral türüne geçersiz kılınabilir:

enum class Enum2 : unsigned int {Val1, Val2};

Eski tarz numaralandırmalarda değerler dış kapsama yerleştirilir. Yeni stil numaralandırmalarla, enum sınıf adının kapsamına yerleştirilirler. Yani yukarıdaki örnekte, Val1tanımsız ama Enum2::Val1tanımlı.

Ayrıca, eski tarz numaralandırmaların açık kapsam belirleme ve temel alınan türün tanımını sağlamasına izin veren bir geçiş sözdizimi de vardır:

enum Enum3 : unsigned long {Val1 = 1, Val2};

Bu durumda, numaralandırıcı adları numaralandırmanın kapsamında ( Enum3::Val1) tanımlanır, ancak geriye dönük uyumluluk için bunlar da çevreleyen kapsama yerleştirilir.

C++ 11'de ileriye dönük numaralandırmalar da mümkündür. Önceden, numaralandırmanın boyutu üyelerinin tanımına bağlı olduğundan, numaralandırma türleri ileriye bildirilemezdi. Numaralandırmanın boyutu örtülü veya açık olarak belirtildiği sürece, ileriye dönük olarak bildirilebilir:

enum Enum1;                      // Invalid in C++03 and C++11; the underlying type cannot be determined.
enum Enum2 : unsigned int;       // Valid in C++11, the underlying type is specified explicitly.
enum class Enum3;                // Valid in C++11, the underlying type is int.
enum class Enum4 : unsigned int; // Valid in C++11.
enum Enum2 : unsigned short;     // Invalid in C++11, because Enum2 was formerly declared with a different underlying type.

Sağ açılı ayraç

C++03'ün ayrıştırıcısı, “ >>” öğesini her durumda sağa kaydırma operatörü veya akış çıkarma operatörü olarak tanımlar . Bununla birlikte, iç içe şablon bildirimlerinde, programcının iki dik açılı ayraç arasına boşluk koymayı ihmal etme ve böylece derleyici sözdizimi hatasına neden olma eğilimi vardır.

C++11, ayrıştırıcının belirtimini iyileştirir, böylece birden çok dik açılı ayraç, makul olduğu yerde şablon argüman listesinin kapatılması olarak yorumlanır. Bu, “ >”, “ >=” veya “ >>” ikili operatörleri kullanılarak parametre ifadelerinin etrafında parantezler kullanılarak geçersiz kılınabilir :

template<bool Test> class SomeType;
std::vector<SomeType<1>2>> x1;  // Interpreted as a std::vector of SomeType<true>,
    // followed by "2 >> x1", which is not valid syntax for a declarator. 1 is true.
std::vector<SomeType<(1>2)>> x1;  // Interpreted as std::vector of SomeType<false>,
    // followed by the declarator "x1", which is valid C++11 syntax. (1>2) is false.

Açık dönüştürme operatörleri

C++98, explicittek argümanlı oluşturucuların örtük tür dönüştürme işleçleri olarak kullanılmasını önlemek için yapıcılar üzerinde bir değiştirici olarak anahtar sözcüğü ekledi . Ancak bu, gerçek dönüştürme operatörleri için hiçbir şey yapmaz. Örneğin, bir akıllı işaretçi sınıfı, operator bool()daha çok ilkel bir işaretçi gibi davranmasına izin verecek bir sınıfa sahip olabilir : bu dönüşümü içeriyorsa, ile test edilebilir if (smart_ptr_variable)(bu, işaretçi boş değilse doğru, aksi takdirde yanlış olur). Ancak bu, diğer istenmeyen dönüşümlere de izin verir. C++ boolaritmetik bir tür olarak tanımlandığından, kullanıcı tarafından amaçlanmayan matematiksel işlemlere izin veren, dolaylı olarak integral ve hatta kayan nokta türlerine dönüştürülebilir.

C++ 11'de explicitanahtar kelime artık dönüştürme operatörlerine uygulanabilir. Yapıcılarda olduğu gibi, bu dönüştürme işlevlerinin örtük dönüştürmelerde kullanılmasını engeller. Ancak, özellikle bir boole değerine ihtiyaç duyan dil bağlamları (if-ifadeleri ve döngülerin koşulları ve mantıksal operatörlere yönelik işlenenler) açık dönüştürmeler olarak sayılır ve bu nedenle bir bool dönüştürme operatörü kullanabilir.

Örneğin, bu özellik safe bool sorununu temiz bir şekilde çözer .

Şablon takma adları

C++03'te, bir typedef'i yalnızca, belirtilen tüm gerçek şablon bağımsız değişkenleriyle birlikte bir şablon uzmanlığının eşanlamlısı da dahil olmak üzere, başka bir türle eşanlamlı olarak tanımlamak mümkündür. typedef şablonu oluşturmak mümkün değildir. Örneğin:

template <typename First, typename Second, int Third>
class SomeType;

template <typename Second>
typedef SomeType<OtherType, Second, 5> TypedefName; // Invalid in C++03

Bu derleme olmayacak.

C++ 11, bu sözdizimiyle bu yeteneği ekler:

template <typename First, typename Second, int Third>
class SomeType;

template <typename Second>
using TypedefName = SomeType<OtherType, Second, 5>;

usingSözdizimi de 11 C ++ türü aliasing olarak kullanılabilir:

typedef void (*FunctionType)(double);       // Old style
using FunctionType = void (*)(double); // New introduced syntax

Sınırsız sendikalar

C++03'te, ne tür nesnelerin bir union. Örneğin, birlikler önemsiz olmayan bir kurucu veya yıkıcı tanımlayan herhangi bir nesne içeremez. C++ 11 bu kısıtlamalardan bazılarını kaldırır.

Bir unionüyenin önemsiz olmayan bir özel üye işlevi varsa , derleyici bunun için eşdeğer üye işlevi oluşturmaz unionve bunun el ile tanımlanması gerekir.

Bu, C++ 11'de izin verilen bir birliğin basit bir örneğidir:

#include <new> // Needed for placement 'new'.

struct Point
{
    Point() {}
    Point(int x, int y): x_(x), y_(y) {} 
    int x_, y_;
};

union U
{
    int z;
    double w;
    Point p; // Invalid in C++03; valid in C++11.
    U() {} // Due to the Point member, a constructor definition is now needed.
    U(const Point& pt) : p(pt) {} // Construct Point object using initializer list.
    U& operator=(const Point& pt) { new(&p) Point(pt); return *this; } // Assign Point object using placement 'new'.
};

Değişiklikler, yalnızca mevcut kuralları gevşettikleri için mevcut herhangi bir kodu bozmaz.

Temel dil işlevi iyileştirmeleri

Bu özellikler, dilin daha önce imkansız olan, aşırı derecede ayrıntılı veya taşınabilir olmayan kitaplıklara ihtiyaç duyan şeyleri yapmasına izin verir.

Değişken şablonlar

C++ 11'de şablonlar değişken sayıda şablon parametresi alabilir. Bu aynı zamanda tip güvenli değişken fonksiyonların tanımlanmasına da izin verir .

Yeni dize değişmezleri

C++03, iki tür dize değişmezi sunar . Çift tırnak içinde yer alan ilk tür, null ile sonlandırılmış bir tür dizisi üretir const char. Olarak tanımlanan ikinci tür L"", tip bir boş sonlandırılmış bir dizi üreten const wchar_t, wchar_ttanımsız boyutunda ve anlam geniş bir karakterdir. Hiçbir hazır bilgi türü, UTF-8 , UTF-16 veya başka herhangi bir Unicode kodlaması içeren dize değişmezleri için destek sağlamaz .

Türün tanımı, charen azından sekiz bitlik bir UTF-8 kodlamasını depolamak için gereken boyut ve derleyicinin temel yürütme karakter kümesinin herhangi bir üyesini içerecek kadar büyük olduğunu açıkça ifade edecek şekilde değiştirildi . Önceden C++ standardında yalnızca ikincisi olarak tanımlanmıştı, daha sonra en az 8 bit garanti etmek için C standardına dayanıyordu.

C++11 üç Unicode kodlamasını destekler: UTF-8 , UTF-16 ve UTF-32 . Tanımında daha önce belirtilen değişikliklerin yanı sıra char, C++11 iki yeni karakter türü ekler: char16_tve char32_t. Bunlar sırasıyla UTF-16 ve UTF-32'yi depolamak için tasarlanmıştır.

Bu kodlamaların her biri için dize değişmezleri oluşturmak şu şekilde yapılabilir:

u8"I'm a UTF-8 string."
u"This is a UTF-16 string."
U"This is a UTF-32 string."

İlk dizenin türü olağandır const char[]. İkinci dizenin türü const char16_t[](küçük harf 'u' ön ekine dikkat edin). Üçüncü dizenin türü const char32_t[](büyük harf 'U' öneki).

Unicode dize değişmezleri oluştururken, Unicode kod noktalarını doğrudan dizeye eklemek genellikle yararlıdır. Bunu yapmak için C++ 11 bu sözdizimine izin verir:

u8"This is a Unicode Character: \u2018."
u"This is a bigger Unicode Character: \u2018."
U"This is a Unicode Character: \U00002018."

'den sonraki \usayı onaltılık bir sayıdır; olağan 0xönek gerektirmez. Tanımlayıcı \u, 16 bitlik bir Unicode kod noktasını temsil eder; 32 bitlik bir kod noktası girmek için \Uve 32 bitlik onaltılık bir sayı kullanın. Yalnızca geçerli Unicode kod noktaları girilebilir. Örneğin, U+D800–U+DFFF aralığındaki kod noktaları yasaktır, çünkü bunlar UTF-16 kodlamalarındaki yedek çiftler için ayrılmıştır.

Ayrıca, özellikle XML dosyalarının değişmez değerlerini , komut dosyası dillerini veya normal ifadeleri kullanmak için, dizelerden manuel olarak kaçmaktan kaçınmak da bazen yararlıdır . C++ 11, bir ham dize değişmezi sağlar:

R"(The String Data \ Stuff " )"
R"delimiter(The String Data \ Stuff " )delimiter"

İlk durumda, "(ve arasındaki her şey )"dizenin bir parçasıdır. "Ve \karakterlerin çıkış olması gerekmez. İkinci durumda, "delimiter(dizeyi başlatır ve yalnızca )delimiter"ulaşıldığında biter . Dize delimiter, boş dize de dahil olmak üzere 16 karaktere kadar herhangi bir dize olabilir. Bu dize boşluk, kontrol karakterleri (, ), veya karakteri içeremez \. Bu sınırlayıcı dizeyi kullanmak, kullanıcının )ham dize değişmezleri içinde karakterlere sahip olmasını sağlar . Örneğin R"delimiter((a-z))delimiter", eşdeğerdir "(a-z)".

Ham dize değişmezleri, geniş değişmez değerle veya Unicode değişmez ön eklerinden herhangi biriyle birleştirilebilir:

u8R"XXX(I'm a "raw UTF-8" string.)XXX"
uR"*(This is a "raw UTF-16" string.)*"
UR"(This is a "raw UTF-32" string.)"

Kullanıcı tanımlı değişmez değerler

C++03 bir dizi değişmez değer sağlar. Karakterler 12.5, derleyici tarafından double12.5 değerine sahip bir tür olarak çözümlenen bir hazır bilgidir. Bununla birlikte, son ekinin eklenmesi f, olduğu gibi 12.5f, float12.5 değerini içeren bir tür değeri oluşturur . Sabit değerler için son ek değiştiricileri, C++ belirtimine göre sabitlenir ve C++03 kodu yeni değişmez değer değiştiricileri oluşturamaz.

Buna karşılık, C++11, kullanıcının değişmezin değiştirdiği karakter dizisini temel alan nesneler oluşturacak yeni tür değişmez değiştiricileri tanımlamasını sağlar.

Değişmez değerlerin dönüşümü iki farklı aşamada yeniden tanımlanır: çiğ ve pişmiş. Ham değişmez, belirli bir türdeki bir karakter dizisidir, pişmiş değişmez ise ayrı bir türdür. 1234Ham değişmez olarak C++ değişmezi , bu '1', '2', '3', karakter dizisidir '4'. Pişmiş bir değişmez olarak, 1234 tamsayıdır 0xA. Ham biçimde C++ değişmezi '0', 'x', 'dir 'A', pişmiş biçimde ise 10 tamsayıdır.

Yalnızca pişmiş biçimde işlenebilen dize değişmezleri dışında, değişmezler hem çiğ hem de pişmiş biçimde genişletilebilir. Bu istisna, dizelerin, söz konusu karakterlerin belirli anlamını ve türünü etkileyen öneklere sahip olması gerçeğinden kaynaklanmaktadır.

Tüm kullanıcı tanımlı değişmezler soneklerdir; önek değişmezlerini tanımlamak mümkün değildir. Alt çizgi ( _) dışında herhangi bir karakterle başlayan tüm ekler standart tarafından ayrılmıştır. Bu nedenle, tüm kullanıcı tanımlı değişmezler, alt çizgi ( _) ile başlayan son eklere sahip olmalıdır .

Değişmezin ham biçimini işleyen kullanıcı tanımlı değişmezler, olarak yazılan bir değişmez işleç aracılığıyla tanımlanır operator "". Bir örnek aşağıdaki gibidir:

OutputType operator "" _mysuffix(const char * literal_string)
{
    // assumes that OutputType has a constructor that takes a const char *
    OutputType ret(literal_string);
    return ret;
}

OutputType some_variable = 1234_mysuffix;
// assumes that OutputType has a get_value() method that returns a double
assert(some_variable.get_value() == 1234.0)

Atama ifadesi OutputType some_variable = 1234_mysuffix;, kullanıcı tanımlı değişmez işlev tarafından tanımlanan kodu yürütür. Bu işlev, "1234"C stili bir dize olarak iletilir , bu nedenle boş bir sonlandırıcıya sahiptir.

Tamsayı ve kayan noktalı ham değişmezleri işlemek için alternatif bir mekanizma, değişken bir şablon aracılığıyladır :

template<char...> OutputType operator "" _tuffix();

OutputType some_variable = 1234_tuffix;
OutputType another_variable = 2.17_tuffix;

Bu, değişmez işleme işlevini şu şekilde başlatır operator "" _tuffix<'1', '2', '3', '4'>(). Bu formda, dizeyi sonlandıran boş karakter yoktur. Bunu yapmanın temel amacı constexpr, derleyicinin değişmezi derleme zamanında tamamen dönüştürmesini sağlamak için C++ 11'in anahtar sözcüğünü kullanmaktır, OutputTypeconstexpr-yapılandırılabilir ve kopyalanabilir bir tür olduğunu ve değişmez işleme işlevinin bir constexprişlev olduğunu varsayar .

Sayısal değişmezler için, pişirilmiş değişmezin türü, ya unsigned long longintegral değişmezler ya da long doublekayan noktalı değişmezler içindir. (Not: İşaret önekli bir hazır bilgi, işareti tekli önek operatörü ve işaretsiz sayı olarak içeren bir ifade olarak çözümlendiğinden, işaretli integral türlerine gerek yoktur.) Alternatif bir şablon formu yoktur:

OutputType operator "" _suffix(unsigned long long);
OutputType operator "" _suffix(long double);

OutputType some_variable = 1234_suffix; // Uses the 'unsigned long long' overload.
OutputType another_variable = 3.1416_suffix; // Uses the 'long double' overload.

Daha önce bahsedilen yeni dize önekleriyle uyumlu olarak, dize değişmezleri için bunlar kullanılır:

OutputType operator "" _ssuffix(const char     * string_values, size_t num_chars);
OutputType operator "" _ssuffix(const wchar_t  * string_values, size_t num_chars);
OutputType operator "" _ssuffix(const char16_t * string_values, size_t num_chars);
OutputType operator "" _ssuffix(const char32_t * string_values, size_t num_chars);

OutputType some_variable =   "1234"_ssuffix; // Uses the 'const char *' overload.
OutputType some_variable = u8"1234"_ssuffix; // Uses the 'const char *' overload.
OutputType some_variable =  L"1234"_ssuffix; // Uses the 'const wchar_t *'  overload.
OutputType some_variable =  u"1234"_ssuffix; // Uses the 'const char16_t *' overload.
OutputType some_variable =  U"1234"_ssuffix; // Uses the 'const char32_t *' overload.

Alternatif bir şablon formu yoktur. Karakter değişmezleri benzer şekilde tanımlanır.

Çok iş parçacıklı bellek modeli

C++11, çok iş parçacıklı programlama desteğini standart hale getirir .

İlgili iki kısım vardır: birden çok iş parçacığının bir programda birlikte var olmasına izin veren bir bellek modeli ve iş parçacıkları arasındaki etkileşim için kitaplık desteği. (Bu makalenin iplik geçirme tesisleri bölümüne bakın .)

Bellek modeli, birden çok iş parçacığının aynı bellek konumuna ne zaman erişebileceğini tanımlar ve bir iş parçacığı tarafından yapılan güncellemelerin diğer iş parçacıklarına ne zaman görünür olacağını belirtir.

İş parçacığı yerel depolama

Çok iş parçacıklı bir ortamda, her iş parçacığının bazı benzersiz değişkenlere sahip olması yaygındır . Bu, bir fonksiyonun yerel değişkenleri için zaten olur, ancak global ve statik değişkenler için olmaz.

Yeni bir iş parçacığı yerel depolama süresi (mevcut statik , dinamik ve otomatik 'e ek olarak ) depolama belirteci tarafından belirtilir thread_local.

Statik depolama süresine sahip olabilecek herhangi bir nesneye (yani, programın tüm yürütülmesini kapsayan yaşam süresi) bunun yerine iş parçacığı yerel süresi verilebilir. Amaç, diğer herhangi bir statik süre değişkeni gibi, bir iş parçacığı yerel nesnesinin bir yapıcı kullanılarak başlatılabilmesi ve bir yıkıcı kullanılarak yok edilebilmesidir.

Açıkça varsayılan ve silinmiş özel üye işlevleri

C++03'te derleyici, bunları kendileri için sağlamayan sınıflar için varsayılan bir kurucu, bir kopya oluşturucu, bir kopya atama operatörü ( operator=) ve bir yıkıcı sağlar. Programcı, özel sürümleri tanımlayarak bu varsayılanları geçersiz kılabilir. C++ ayrıca operator new, programcının geçersiz kılabileceği tüm sınıflar üzerinde çalışan birkaç global işleç (örneğin ) tanımlar .

Ancak, bu varsayılanları oluşturma üzerinde çok az kontrol vardır. Örneğin, bir sınıfı doğası gereği kopyalanamaz yapmak, özel bir kopya oluşturucu ve kopya atama operatörü bildirmeyi ve bunları tanımlamamayı gerektirir. Bu işlevleri kullanmaya çalışmak, Tek Tanım Kuralı'nın (ODR) ihlalidir . Teşhis mesajı gerekli olmasa da, ihlaller bir bağlayıcı hatasına neden olabilir.

Varsayılan kurucu durumunda, bir sınıf herhangi bir kurucu ile tanımlanmışsa, derleyici varsayılan bir kurucu oluşturmaz. Bu, birçok durumda yararlıdır, ancak hem özel kuruculara hem de derleyici tarafından oluşturulan varsayılana sahip olmak da yararlıdır.

C++11, bu özel üye işlevlerinin açık bir şekilde varsayılan hale getirilmesine ve silinmesine izin verir. Örneğin, bu tür, varsayılan kurucuyu kullandığını açıkça bildirir:

struct SomeType
{
    SomeType() = default; //The default constructor is explicitly stated.
    SomeType(OtherType value);
};

Alternatif olarak, belirli özellikler açıkça devre dışı bırakılabilir. Örneğin, bu tür kopyalanamaz:

struct NonCopyable
{
    NonCopyable() = default;
    NonCopyable(const NonCopyable&) = delete;
    NonCopyable& operator=(const NonCopyable&) = delete;
};

= deleteBelirteci belirli parametrelerle bir üye işlev arama izin vermemek için kullanılabilen herhangi bir fonksiyon, arama yasaklamak için kullanılabilir. Örneğin:

struct NoInt
{
    void f(double i);
    void f(int) = delete;
};

Görüşme denemesi f()bir ile intyerine kadar sessiz dönüştürme gerçekleştirme, derleyici tarafından reddedilecektir double. Bu, işlevin doubleaşağıdakiler dışında herhangi bir türde çağrılmasına izin vermemek için genelleştirilebilir :

struct OnlyDouble
{
    void f(double d);
    template<class T> void f(T) = delete;
};

Tip long long int

C++03'te en büyük tamsayı türü long int. En az olduğu kadar kullanılabilir bit olması garanti edilir int. Bu long int, bazı popüler uygulamalarda 64 bit ve diğerlerinde 32 bit boyutuna sahip olmasına neden oldu . C++11, long long intbu sorunu gidermek için yeni bir tamsayı türü ekler . En az a kadar büyük long intolması ve 64 bitten az olmaması garanti edilir . Tür başlangıçta C99 tarafından standart C'ye tanıtıldı ve çoğu C++ derleyicisi onu zaten bir uzantı olarak destekledi.

Statik iddialar

C++03, iddiaları test etmek için iki yöntem sağlar : makro assertve önişlemci yönergesi #error. Bununla birlikte, hiçbiri şablonlarda kullanım için uygun değildir: makro, iddiayı yürütme zamanında test ederken, önişlemci yönergesi, şablonların somutlaştırılmasından önce gerçekleşen ön işleme sırasında iddiayı test eder. Şablon parametrelerine bağlı özellikleri test etmek için de uygun değildir.

Yeni yardımcı program, new anahtar sözcüğünü kullanarak, iddiaları derleme zamanında test etmenin yeni bir yolunu sunar static_assert. Beyanname şu şekli alır:

static_assert (constant-expression, error-message);

İşte nasıl static_assertkullanılabileceğine dair bazı örnekler :

static_assert((GREEKPI > 3.14) && (GREEKPI < 3.15), "GREEKPI is inaccurate!");
template<class T>
struct Check
{
    static_assert(sizeof(int) <= sizeof(T), "T is not big enough!");
};
template<class Integral>
Integral foo(Integral x, Integral y)
{
    static_assert(std::is_integral<Integral>::value, "foo() parameter must be an integral type.");
}

Sabit ifade olduğunda false, derleyici bir hata mesajı üretir. İlk örnek, önişlemci yönergesine benzer #error, ancak önişlemci yalnızca integral türlerini destekler. Buna karşılık, ikinci örnekte iddia, şablon sınıfının her örneğinde kontrol edilir Check.

Statik iddialar, şablonların dışında da yararlıdır. Örneğin, bir algoritmanın belirli bir uygulaması , standardın garanti etmediği long longbir intşey olan bir 'den daha büyük bir varlığın boyutuna bağlı olabilir . Böyle bir varsayım, çoğu sistem ve derleyici için geçerlidir, ancak hepsi için geçerli değildir.

sizeofAçık bir nesne olmadan sınıf üyeleri üzerinde çalışmaya izin ver

C++03'te sizeofoperatör, türler ve nesneler üzerinde kullanılabilir. Ancak bunu yapmak için kullanılamaz:

struct SomeType { OtherType member; };

sizeof(SomeType::member); // Does not work with C++03. Okay with C++11

Bu, boyutunu döndürmelidir OtherType. C++03 buna izin vermez, dolayısıyla bu bir derleme hatasıdır. C++ 11 buna izin verir. alignofC++11'de tanıtılan operatör için de izin verilir .

Nesne hizalamasını kontrol etme ve sorgulama

C ++ 11, değişken uyum sorgulanan ile kontrol edilmesini sağlar alignofve alignas.

alignofOperatör türü alır ve (a olarak türü örnekleri tahsis edilmesi gereken 2 bayt sınırında gücünü verir std::size_t). Bir başvuru türü verildiğinde alignof, başvurulan türün hizalamasını döndürür; diziler için öğe türünün hizalamasını döndürür.

alignasBelirteci bir değişken için bellek hizalama kontrol eder. Belirtici bir sabit veya bir tür alır; sağlandığında bir tür alignas(T)kısaltmasıdır alignas(alignof(T)). Örneğin, bir char dizisinin bir kayan noktayı tutacak şekilde uygun şekilde hizalanması gerektiğini belirtmek için:

alignas(float) unsigned char c[sizeof(float)]

Çöp toplanan uygulamalara izin ver

Programcı tarafından yönlendirilen çöp toplama için önceki C++ standartları sağlandı set_new_handler, ancak otomatik çöp toplama amacıyla nesne erişilebilirliği tanımı vermedi. C++11, işaretçi değerlerinin diğer değerlerden "güvenli bir şekilde türetildiği" koşulları tanımlar. Bir uygulama, katı işaretçi güvenliği altında çalıştığını belirtebilir, bu durumda bu kurallara göre türetilmemiş işaretçiler geçersiz hale gelebilir.

Öznitellikler

C++11, dile derleyici/araç uzantıları için standart bir sözdizimi sağlar. Bu tür uzantılar geleneksel olarak #pragmayönerge veya satıcıya özel anahtar sözcükler kullanılarak belirtilir ( __attribute__GNU ve __declspecMicrosoft için olduğu gibi ). Yeni sözdizimi ile eklenen bilgiler, çift köşeli parantez içine alınmış bir öznitelik biçiminde belirtilebilir. Kaynak kodun çeşitli öğelerine bir nitelik uygulanabilir:

int [[attr1]] i [[attr2, attr3]];

[[attr4(arg1, arg2)]] if (cond)
{
    [[vendor::attr5]] return i;
}

Yukarıdaki örnekte, nitelik attr1değişkenin türüne de geçerlidir i, attr2ve attr3kendisi değişken için geçerli, attr4geçerli ifdeyimi ve vendor::attr5iade deyimi için de geçerlidir. Genel olarak (ancak bazı istisnalar dışında), adlandırılmış bir varlık için belirtilen bir nitelik, addan sonra ve varlıktan önce yerleştirilir, aksi takdirde, yukarıda gösterildiği gibi, bir çift çift köşeli parantez içinde birkaç nitelik listelenebilir, ek argümanlar sağlanabilir bir öznitelik için ve özniteliklerin kapsamı satıcıya özel öznitelik ad alanları tarafından belirlenebilir.

Niteliklerin dil semantik anlamı olmaması ve göz ardı edildiğinde programın anlamını değiştirmemesi önerilir. Öznitelikler, örneğin derleyicinin daha iyi tanılama yapmasına veya oluşturulan kodu optimize etmesine yardımcı olan bilgileri sağlamak için yararlı olabilir.

C++11 iki standart öznitelik sağlar: noreturnbir işlevin dönmediğini carries_dependencybelirtmek ve işlev bağımsız değişkenlerinin veya dönüş değerinin bir bağımlılık taşıdığını belirterek çok iş parçacıklı kodu optimize etmeye yardımcı olmak.

C++ standart kitaplığı değişiklikleri

C++11 standart kitaplığında bir dizi yeni özellik tanıtıldı. Bunların çoğu eski standart altında uygulanabilirdi, ancak bazıları (az ya da çok) yeni C++11 temel özelliklerine güveniyor.

Yeni kütüphanelerin büyük bir kısmı, 2005'te yayınlanan C++ Standartları Komitesi'nin Kütüphane Teknik Raporunda (TR1 olarak adlandırılır) tanımlanmıştır. TR1'in çeşitli tam ve kısmi uygulamaları şu anda ad alanı kullanılarak mevcuttur std::tr1. C++ 11 için ad alanına taşındılar std. Ancak, TR1 özellikleri C++11 standart kitaplığına getirildiğinden, uygun olan yerlerde, ilk TR1 sürümünde bulunmayan C++11 dil özellikleriyle yükseltildiler. Ayrıca, C++03 altında mümkün olan ancak orijinal TR1 spesifikasyonunun parçası olmayan özelliklerle geliştirilmiş olabilirler.

Standart kitaplık bileşenlerine yükseltmeler

C++11, mevcut standart kitaplık bileşenlerinin yararlanabileceği bir dizi yeni dil özelliği sunar. Örneğin, çoğu standart kitaplık kapsayıcısı, hem ağır kapsayıcıları hızla hareket ettirmek hem de bu kapsayıcıların içeriklerini yeni bellek konumlarına taşımak için Rvalue referansına dayalı hareket oluşturucu desteğinden yararlanabilir. Standart kitaplık bileşenleri, uygun olan yerlerde yeni C++11 dil özellikleriyle yükseltildi. Bunlar aşağıdakileri içerir, ancak bunlarla sınırlı değildir:

  • Değer referansları ve ilgili hareket desteği
  • UTF-16 kodlama birimi ve UTF-32 kodlama birimi Unicode karakter türleri için destek
  • Değişken şablonlar (mükemmel yönlendirmeye izin vermek için Rvalue referanslarıyla birleştirilmiştir)
  • Derleme zamanı sabit ifadeleri
  • decltype
  • explicit dönüştürme operatörleri
  • Varsayılan veya silinmiş olarak bildirilen işlevler

Ayrıca, önceki C++ standardından bu yana çok zaman geçti. Standart kitaplığı kullanarak birçok kod yazılmıştır. Bu, standart kitaplıkların bazı iyileştirmeler kullanabilecek bölümlerini ortaya çıkardı. Göz önünde bulundurulan birçok iyileştirme alanı arasında standart kitaplık ayırıcıları vardı . Önceki modeli desteklemek için C++ 11'e kapsam tabanlı yeni bir ayırıcı modeli dahil edildi.

Diş açma tesisleri

C++03 dili, iş parçacığı oluşturmayı destekleyen bir bellek modeli sağlarken, iş parçacığı oluşturmayı gerçekten kullanmak için birincil destek, C++11 standart kitaplığıyla birlikte gelir.

Yeni iş parçacığında çalıştırmak std::threadiçin bir işlev nesnesi (ve ona iletilecek isteğe bağlı bir dizi argüman ) alan bir iş parçacığı sınıfı ( ) sağlanır . std::thread::join()Üye işlevi aracılığıyla iş parçacığı birleştirme desteği sağlayarak, başka bir yürütme iş parçacığı tamamlanana kadar bir iş parçacığının durmasına neden olmak mümkündür . Mümkün olduğunda, üye işlevi tarafından platforma özgü işlemler için temeldeki yerel iş parçacığı nesnesine/nesnelerine erişim sağlanır std::thread::native_handle().

İş parçacıkları arasında senkronizasyon için uygun muteksler ( std::mutex, std::recursive_mutex, vb.) ve koşul değişkenleri ( std::condition_variableve std::condition_variable_any) kitaplığa eklenir. Bunlara, Kaynak Edinme Başlatılıyor (RAII) kilitleri ( std::lock_guardve std::unique_lock) ve kolay kullanım için kilitleme algoritmaları aracılığıyla erişilebilir .

Yüksek performanslı, düşük seviyeli çalışma için, bazen mutekslerin yükü olmadan iş parçacıkları arasında iletişim gerekir. Bu, bellek konumlarında atomik işlemler kullanılarak yapılır . Bunlar isteğe bağlı olarak bir işlem için gereken minimum bellek görünürlük kısıtlamalarını belirleyebilir. Açık bellek engelleri de bu amaç için kullanılabilir.

C++11 iş parçacığı kitaplığı, aynı zamanda, iş parçacıkları arasında eşzamansız sonuçların iletilmesi vestd::packaged_task böyle bir eşzamansız sonuç üretebilecek bir işlev çağrısının tamamlanması için vadeli işlemler ve vaatler içerir . Vadeli işlem teklifi eleştirildi, çünkü vadeli işlemleri birleştirmenin ve bir dizi vaat içinde bir sözün tamamlanıp tamamlanmadığını kontrol etmenin bir yolundan yoksundu.

İplik havuzları gibi daha ileri düzey iş parçacığı oluşturma tesisleri , gelecekteki bir C++ teknik raporuna geri gönderilmiştir . C++ 11'in parçası değiller, ancak nihai uygulamalarının tamamen iş parçacığı kitaplığı özelliklerinin üzerine inşa edilmesi bekleniyor.

Yeni std::asynctesis, görevleri yürütmek ve bunları bir std::future. Kullanıcı, görevin ayrı bir iş parçacığında eşzamansız olarak mı yoksa değeri bekleyen bir iş parçacığında eşzamanlı olarak mı çalıştırılacağını seçebilir. Varsayılan olarak, uygulama, aşırı abonelik olmadan donanım eşzamanlılığından yararlanmanın kolay bir yolunu sağlayan ve basit kullanımlar için bir iş parçacığı havuzunun bazı avantajlarını sağlayan seçim yapabilir.

demet türleri

Tuple'lar , önceden düzenlenmiş boyutlardaki heterojen nesnelerden oluşan koleksiyonlardır. Bir demet, bir yapının üye değişkenlerinin bir genellemesi olarak düşünülebilir.

TR1 tanımlama grubu türünün C++11 sürümü, değişken şablonlar gibi C++11 özelliklerinden yararlandı . Makul bir şekilde uygulamak için TR1 sürümü, uygulama tarafından tanımlanan maksimum sayıda içerilen tür ve önemli makro hileler gerektiriyordu. Buna karşılık, C++ 11 sürümünün uygulanması, açık bir uygulama tanımlı maksimum tür sayısı gerektirmez. Derleyiciler şablon örneklemesi için dahili bir maksimum özyineleme derinliğine sahip olsalar da (ki bu normaldir), tanımlama gruplarının C++ 11 sürümü bu değeri kullanıcıya göstermez.

Değişken şablonları kullanarak , tanımlama grubu sınıfının bildirimi aşağıdaki gibi görünür:

template <class ...Types> class tuple;

Tuple türünün tanımına ve kullanımına bir örnek:

typedef std::tuple <int, double, long &, const char *> test_tuple;
long lengthy = 12;
test_tuple proof (18, 6.5, lengthy, "Ciao!");

lengthy = std::get<0>(proof);  // Assign to 'lengthy' the value 18.
std::get<3>(proof) = " Beautiful!";  // Modify the tuple’s fourth element.

İçeriğini prooftanımlamadan demeti oluşturmak mümkündür , ancak yalnızca demet öğelerinin türleri varsayılan kuruculara sahipse. Ayrıca, bir demeti başka bir demete atamak mümkündür: eğer iki demet tipi aynıysa, her eleman tipi bir kopya kurucuya sahip olmalıdır; aksi takdirde, sağ taraftaki demetin her eleman tipi, sol taraftaki demetin karşılık gelen eleman tipine dönüştürülebilir olmalıdır veya sol taraftaki demetin karşılık gelen eleman tipinin uygun bir kurucuya sahip olması gerekir.

typedef std::tuple <int , double, string       > tuple_1 t1;
typedef std::tuple <char, short , const char * > tuple_2 t2 ('X', 2, "Hola!");
t1 = t2; // Ok, first two elements can be converted,
         // the third one can be constructed from a 'const char *'.

için olduğu gibi , tür kesintisini kullanarak otomatik olarak s oluşturmak std::make_pairiçin std::pairvardır ve böyle bir Tuple bildirmeye yardımcı olur. demetleri açmaya yardımcı olmak için değer referansları demetleri oluşturur. burada da yardımcı olur. Örneğe bakın: std::make_tuplestd::tupleautostd::tiestd::ignore

auto record = std::make_tuple("Hari Ram", "New Delhi", 3.5, 'A');
std::string name ; float gpa ; char grade ;
std::tie(name, std::ignore, gpa, grade) = record ; // std::ignore helps drop the place name
std::cout << name << ' ' << gpa << ' ' << grade << std::endl ;

İlişkisel operatörler mevcuttur (aynı sayıda elemana sahip demetler arasında) ve bir demetin özelliklerini kontrol etmek için iki ifade mevcuttur (yalnızca derleme sırasında):

  • std::tuple_size<T>::valuetuple içindeki öğelerin sayısını döndürür T,
  • std::tuple_element<I, T>::typeNesne numara tipini verir Ituple T.

Hash tabloları

C++ standart kitaplığına karma tabloların (sırasız ilişkisel kapsayıcılar) dahil edilmesi, en çok tekrarlanan isteklerden biridir. Yalnızca zaman kısıtlamaları nedeniyle C++03'te benimsenmedi. Karma tablolar, en kötü durumda (birçok çarpışmanın varlığında) dengeli bir ağaçtan daha az verimli olsa da , birçok gerçek uygulamada daha iyi performans gösterirler.

Çatışmalar yalnızca doğrusal zincirleme yoluyla yönetilir, çünkü komite, oldukça fazla içsel sorun ortaya çıkaran (özellikle öğelerin silinmesi kabul edildiğinde) açık adresleme çözümlerini standartlaştırmanın uygun olduğunu düşünmedi . Kendi hash tablosu uygulamalarını geliştiren standart olmayan kütüphanelerle isim çakışmalarını önlemek için "hash" yerine "sırasız" öneki kullanıldı.

Yeni kitaplık, aynı anahtara (benzersiz anahtarlar veya eşdeğer anahtarlar) sahip öğeleri kabul edip etmemelerine ve her anahtarı ilişkili bir değere eşleyip eşlememelerine göre farklılık gösteren dört tür karma tabloya sahiptir. Bir sıralanmamış_ öneki ile mevcut dört ikili arama ağacı tabanlı ilişkisel kapsayıcıya karşılık gelirler .

Hash tablosunun türü ilişkili değerler Eşdeğer anahtarlar
std::unordered_set Numara Numara
std::unordered_multiset Numara Evet
std::unordered_map Evet Numara
std::unordered_multimap Evet Evet

Yeni sınıflar, bir kapsayıcı sınıfının tüm gereksinimlerini karşılar ve öğelere erişmek için gereken tüm yöntemlere sahiptir: insert, erase, begin, end.

Bu yeni özellik, herhangi bir C++ dil çekirdek uzantısına ihtiyaç duymadı (gerçi uygulamalar çeşitli C++11 dil özelliklerinden yararlanacak), yalnızca başlığın küçük bir uzantısı <functional>ve başlıkların <unordered_set>ve <unordered_map>. Mevcut standart sınıflarda başka bir değişiklik gerekli değildir ve standart kitaplığın diğer uzantılarına bağlı değildir.

Düzenli ifadeler

Yeni başlıkta tanımlanan yeni kitaplık, <regex>birkaç yeni sınıftan oluşur:

  • normal ifadeler , şablon sınıfının örneğiyle temsil edilir std::regex;
  • olaylar, şablon sınıfının örneğiyle temsil edilir std::match_results.

İşlev std::regex_searcharama için kullanılırken, 'ara ve değiştir' için std::regex_replaceyeni bir dize döndüren işlev kullanılır. Algoritmalar std::regex_searchve std::regex_replacedüzenli bir ifade ve bir dize alır ve struct içinde bulunan oluşumları yazar std::match_results.

İşte kullanımına bir örnek std::match_results:

const char *reg_esp = "[ ,.\\t\\n;:]"; // List of separator characters.

// this can be done using raw string literals:
// const char *reg_esp = R"([ ,.\t\n;:])";

std::regex rgx(reg_esp); // 'regex' is an instance of the template class
                         // 'basic_regex' with argument of type 'char'.
std::cmatch match; // 'cmatch' is an instance of the template class
                   // 'match_results' with argument of type 'const char *'.
const char *target = "Unseen University - Ankh-Morpork";

// Identifies all words of 'target' separated by characters of 'reg_esp'.
if (std::regex_search(target, match, rgx))
{
    // If words separated by specified characters are present.

    const size_t n = match.size();
    for (size_t a = 0; a < n; a++)
    {
        std::string str (match[a].first, match[a].second);
        std::cout << str << "\n";
    }
}

Çift ters eğik çizgi kullanımına dikkat edin , çünkü C++ çıkış karakteri olarak ters eğik çizgi kullanır. Sorunu önlemek için C++11 ham dize özelliği kullanılabilir.

Kitaplık <regex>, ne mevcut herhangi bir başlığın değiştirilmesini (gerçi bunları uygun olduğunda kullanacaktır) ne de çekirdek dilin bir uzantısını gerektirir. In POSIX C, düzenli ifadeler de mevcuttur C POSIX kütüphanesi # regex.h .

Genel amaçlı akıllı işaretçiler

C++11, TR1'e ve TR1'den std::unique_ptriyileştirmeler sağlar . kullanımdan kaldırıldı. std::shared_ptrstd::weak_ptrstd::auto_ptr

Genişletilebilir rastgele sayı tesisi

C standart kitaplığı , işlev aracılığıyla sözde rasgele sayılar üretme yeteneği sağlar rand. Ancak, algoritma tamamen kitaplık satıcısına devredilmiştir. C++ bu işlevi hiçbir değişiklik olmadan devraldı, ancak C++ 11, sözde rasgele sayılar oluşturmak için yeni bir yöntem sağlar.

C++11'in rasgele sayı işlevi iki kısma ayrılır: rasgele sayı üretecinin durumunu içeren ve sözde rasgele sayıları üreten bir üreteç motoru; ve sonucun aralığını ve matematiksel dağılımını belirleyen bir dağılım . Bu ikisi bir rasgele sayı üreteci nesnesi oluşturmak için birleştirilir.

C standardından farklı olarak rand, C++11 mekanizması üç temel oluşturucu motor algoritması ile birlikte gelir:

C++11 ayrıca bir dizi standart dağıtım sağlar:

Jeneratör ve dağıtımlar bu örnekte olduğu gibi birleştirilir:

#include <random>
#include <functional>

std::uniform_int_distribution<int> distribution(0, 99);
std::mt19937 engine; // Mersenne twister MT19937
auto generator = std::bind(distribution, engine);
int random = generator(); // Generate a uniform integral variate between 0 and 99.
int random2 = distribution(engine); // Generate another sample directly using the distribution and the engine objects.

sarmalayıcı referansı

Şablon sınıfının bir örneğinden bir sarmalayıcı başvurusu elde edilir reference_wrapper. Sarmalayıcı başvuruları &, C++ dilinin normal başvurularına (' ') benzer . Herhangi bir nesneden sarmalayıcı referansı elde etmek için fonksiyon şablonu refkullanılır (sabit bir referans crefiçin kullanılır).

Sarmalayıcı referansları, her şeyden önce, kopyalardan ziyade parametrelere referansların gerekli olduğu işlev şablonları için yararlıdır:

// This function will obtain a reference to the parameter 'r' and increment it.
void func (int &r)  { r++; }

// Template function.
template<class F, class P> void g (F f, P t)  { f(t); }

int main()
{
    int i = 0;
    g (func, i); // 'g<void (int &r), int>' is instantiated
                 // then 'i' will not be modified.
    std::cout << i << std::endl; // Output -> 0

    g (func, std::ref(i)); // 'g<void(int &r),reference_wrapper<int>>' is instantiated
                           // then 'i' will be modified.
    std::cout << i << std::endl; // Output -> 1
}

Bu yeni yardımcı program mevcut <utility>başlığa eklendi ve C++ dilinin başka uzantılarına ihtiyaç duymadı.

İşlev nesneleri için polimorfik sarmalayıcılar

İşlev nesneleri için polimorfik sarmalayıcılar , anlambilim ve sözdizimindeki işlev işaretçilerine benzer , ancak daha az sıkı bağlıdır ve bağımsız değişkenleri sarmalayıcınınkilerle uyumlu olan çağrılabilecek herhangi bir şeye (işlev işaretçileri, üye işlev işaretçileri veya işlevler) ayrım gözetmeksizin başvurabilir. .

Bir örnek özelliklerini netleştirebilir:

std::function<int (int, int)> func; // Wrapper creation using
                                    // template class 'function'.
std::plus<int> add; // 'plus' is declared as 'template<class T> T plus( T, T ) ;'
                    // then 'add' is type 'int add( int x, int y )'.
func = add;  // OK - Parameters and return types are the same.

int a = func (1, 2); // NOTE: if the wrapper 'func' does not refer to any function,
                     // the exception 'std::bad_function_call' is thrown.

std::function<bool (short, short)> func2 ;
if (!func2)
{
    // True because 'func2' has not yet been assigned a function.

    bool adjacent(long x, long y);
    func2 = &adjacent; // OK - Parameters and return types are convertible.

    struct Test
    {
        bool operator()(short x, short y);
    };
    Test car;
    func = std::ref(car); // 'std::ref' is a template function that returns the wrapper
                          // of member function 'operator()' of struct 'car'.
}
func = func2; // OK - Parameters and return types are convertible.

Şablon sınıfı function, <functional>C++ dilinde herhangi bir değişikliğe gerek kalmadan başlık içinde tanımlanmıştır .

Metaprogramlama için tip özellikleri

Metaprogramlama , başka bir programı (veya kendisini) oluşturan veya değiştiren bir program oluşturmaktan oluşur. Bu, derleme sırasında veya yürütme sırasında olabilir. C ++ Standartları Komitesi şablonlar aracılığıyla derleme sırasında metaprogramming sağlayan bir kütüphane koymaya karar verdi.

A: burada meta-bir program örneğidir C ++ 03 standardı kullanılarak, bir Özyinelemeyi tamsayı üs hesaplanması için şablon örnekleri:

template<int B, int N>
struct Pow
{
    // recursive call and recombination.
    enum{ value = B*Pow<B, N-1>::value };
};

template< int B >
struct Pow<B, 0>
{
    // ''N == 0'' condition of termination.
    enum{ value = 1 };
};
int quartic_of_three = Pow<3, 4>::value;

Birçok algoritma, farklı veri türleri üzerinde çalışabilir; C++'ın şablonları, genel programlamayı destekler ve kodu daha kompakt ve kullanışlı hale getirir. Bununla birlikte, algoritmaların kullanılan veri türleri hakkında bilgiye ihtiyaç duyması yaygındır. Bu bilgi, tür özellikleri kullanılarak bir şablon sınıfının somutlaştırılması sırasında çıkarılabilir .

Tip özellikleri , bir nesnenin kategorisini ve bir sınıfın (veya bir yapının) tüm özelliklerini tanımlayabilir. Yeni başlıkta tanımlanırlar <type_traits>.

Bir sonraki örnekte, verilen veri türlerine bağlı olarak önerilen iki algoritmadan birini ( algorithm.do_it) somutlaştıracak olan 'ayrıntılı' şablon işlevi vardır .

// First way of operating.
template< bool B > struct Algorithm
{
    template<class T1, class T2> static int do_it (T1 &, T2 &)  { /*...*/ }
};

// Second way of operating.
template<> struct Algorithm<true>
{
    template<class T1, class T2> static int do_it (T1, T2)  { /*...*/ }
};

// Instantiating 'elaborate' will automatically instantiate the correct way to operate.
template<class T1, class T2>
int elaborate (T1 A, T2 B)
{
    // Use the second way only if 'T1' is an integer and if 'T2' is
    // in floating point, otherwise use the first way.
    return Algorithm<std::is_integral<T1>::value && std::is_floating_point<T2>::value>::do_it( A, B ) ;
}

Via tip özellikleri başlığında tanımlandığı <type_traits>, bu tip transformasyon oluşturma işlemleri (mümkündür static_castve const_castbir şablon içinde yetersiz).

Bu tür bir programlama zarif ve özlü kod üretir; ancak bu tekniklerin zayıf noktası hata ayıklamadır: derleme sırasında rahatsız edici ve program yürütme sırasında çok zor.

İşlev nesnelerinin dönüş türünü hesaplamak için tek tip yöntem

Bir şablon işlev nesnesinin dönüş türünü derleme zamanında belirlemek, özellikle dönüş değeri işlevin parametrelerine bağlıysa, sezgisel değildir. Örnek olarak:

struct Clear
{
    int    operator()(int) const;    // The parameter type is
    double operator()(double) const; // equal to the return type.
};

template <class Obj>
class Calculus
{
public:
    template<class Arg> Arg operator()(Arg& a) const
    {
        return member(a);
    }
private:
    Obj member;
};

Sınıf şablonunu başlatırken, Calculus<Clear>işlev nesnesi calculusher zaman işlevinin işlev nesnesi ile aynı dönüş türüne sahip olacaktır Clear. Ancak, Confusedaşağıda verilen sınıf :

struct Confused
{
    double operator()(int) const;     // The parameter type is not
    int    operator()(double) const;  // equal to the return type.
};

Örneklemeye çalışmak Calculus<Confused>, dönüş türünün sınıfınkiyle Calculusaynı olmamasına neden olur Confused. Derleyici dönüştürme ilgili uyarıları oluşturabilir intiçin doubleve tersi de geçerlidir.

TR1, std::result_ofher bildirim için bir işlev nesnesinin dönüş türünü belirlemeye ve kullanmaya izin veren şablon sınıfını sunar ve C++11 benimser . Nesne , işlev nesnesinin dönüş türünü türetmek için nesneyi CalculusVer2kullanır std::result_of:

template< class Obj >
class CalculusVer2
{
public:
    template<class Arg>
    typename std::result_of<Obj(Arg)>::type operator()(Arg& a) const
    {
        return member(a);
    }
private:
    Obj member;
};

Bu şekilde, function nesnesinin örneklerinde CalculusVer2<Confused>hiçbir dönüştürme, uyarı veya hata olmaz.

TR1 sürümünden tek değişiklik, TR1 sürümünün std::result_ofbir uygulamanın bir işlev çağrısının sonuç türünü belirleyememesine izin vermesidir. Desteklemek için C++'da yapılan değişiklikler nedeniyle decltype, C++11 sürümünün std::result_ofartık bu özel durumlara ihtiyacı yoktur; uygulamalar her durumda bir türü hesaplamak için gereklidir.

Geliştirilmiş C uyumluluğu

C99'dan C ile uyumluluk için şunlar eklendi:

  • Önişlemci:
    • değişken makrolar ,
    • bitişik dar/geniş dize değişmezlerinin birleştirilmesi,
    • _Pragma()- eşdeğeri #pragma.
  • long long – en az 64 bit uzunluğunda tamsayı türü.
  • __func__ – içinde bulunduğu fonksiyonun adına göre değerlendirme yapan makro.
  • Başlıklar:
    • cstdbool( stdbool.h),
    • cstdint( stdint.h),
    • cinttypes( inttypes.h).

Başlangıçta planlanmış ancak kaldırılmış veya dahil edilmemiş özellikler

Ayrı bir TR'ye yönelmek:

  • Modüller
  • Ondalık türleri
  • Matematik özel fonksiyonlar

Ertelenen:

  • kavramlar
  • Daha eksiksiz veya gerekli çöp toplama desteği
  • Refleks
  • Makro kapsamları

Kaldırılan veya kullanımdan kaldırılan özellikler

Sıralama noktası terimi kaldırıldı, yerine bir işlemin diğerinden önce sıralandığını veya iki işlemin sırasız olduğunu belirterek değiştirildi.

Anahtar kelimenin önceki kullanımı exportkaldırıldı. Anahtar kelimenin kendisi kalır ve gelecekteki potansiyel kullanım için ayrılmıştır.

Dinamik istisna belirtimleri kullanımdan kaldırılmıştır. İstisna olmayan fırlatma işlevlerinin derleme zamanı belirtimi, noexceptoptimizasyon için yararlı olan anahtar sözcükle kullanılabilir.

std::auto_ptrtarafından yürürlükten kaldırılmış, kullanımdan kaldırılmıştır std::unique_ptr.

İşlev nesnesi temel sınıfları ( std::unary_function, std::binary_function), işlevlere işaretçilere bağdaştırıcılar ve üyelere işaretçilere bağdaştırıcılar ve bağlayıcı sınıflarının tümü kullanımdan kaldırılmıştır.

Ayrıca bakınız

Referanslar

Dış bağlantılar