C ++ 11'de hangi kırılma değişiklikleri getirildi?


227

Bazı eski kod derleme durmasına neden olacak C + + 11 değişikliklerden en az birini biliyorum: explicit operator bool()standart kütüphaneye giriş, eski örnekleri yerine operator void*(). Verilen, bunun kırılacağı kod muhtemelen ilk etapta geçerli olmaması gereken bir koddur, ancak yine de hala bir değişikliktir: eskiden geçerli olan programlar artık geçerli değildir.

Başka kırılma değişiklikleri var mı?


1
exportAnahtar kelimenin anlamı kaldırılsın mı? Bana mont getireyim.
Steve Jessop

7
Biliyor musun, boola dönüşüme “kırılma değişikliği” diyemeyeceğim ... daha çok “cezalandırıcı bir değişiklik” gibi.
Xeo

4
Böyle bir birlik oluşturmak için gerekli olan tüm evraklar sadece lastik damgalamayı beklerken, neden olmasın?
Dennis Zickefoose

3
@Xeo: mystream.good()ile aynı değil bool(mystream)mi? good()hiçbir bayrak ayarlanmadıysa doğrudur. bool(mystream)yalnızca eofbitayarlanmışsa hala yanlıştır . !mystream.fail()doğru eşdeğer olacaktır.
R. Martinho Fernandes

2
Moderatör notu : " Lütfen soru veya cevap ile konuyla ilgili yorumları tutun. Bir soru veya cevap tartışılırken, tartışma sadece bu soru veya cevap ile ilgili olmalıdır. Tartışma, genel olarak Yığın Taşması için yapıcı değildir. Kesinlikle antagonize değil. "
Tim Post

Yanıtlar:


178

FDIS'in C.2"C ++ ve ISO C ++ 2003" ekinde uyumsuzluklar için bir bölüm vardır .

Özet, burada FDIS'i açıklayarak, daha iyi bir SO yanıtı olarak uygun hale getirmek için. Farklılıkları göstermek için kendi örneklerimi ekledim.

Etkilerini tam olarak bilmediğim birkaç kütüphane ile ilgili uyumsuzluk var, bu yüzden bunları başkalarının üzerinde durması için bırakıyorum.

Çekirdek dil


#define u8 "abc"
const char *s = u8"def"; // Previously "abcdef", now "def"

#define _x "there"
"hello"_x // now a user-defined-string-literal. Previously, expanded _x .

Yeni anahtar kelimeler: alignas, alignof, char16_t, char32_t, constexpr, decltype, noexcept, nullptr, static_assert ve thread_local


Uzun ile temsil edilebilenden daha büyük belirli tamsayı değişmezleri, işaretsiz bir tamsayı türünden uzun süre imzalı olarak değişebilir.


Tamsayı bölme kullanan geçerli C ++ 2003 kodu sonucu 0'a veya negatif sonsuza doğru yuvarlar, oysa C ++ 0x her zaman sonucu 0'a yuvarlar.

(kuşkusuz çoğu insan için bir uyumluluk sorunu değildir).


Anahtar kelimeyi autodepolama sınıfı belirleyicisi olarak kullanan geçerli C ++ 2003 kodu C ++ 0x'de geçersiz olabilir.


Dönüşümleri daraltmak, C ++ 03 ile uyumsuzluklara neden olur. Örneğin, aşağıdaki kod C ++ 2003'te geçerlidir ancak bu Uluslararası Standartta geçersizdir, çünkü çiftten int'e daralma dönüşümüdür:

int x[] = { 2.0 };

Örtük olarak bildirilen özel üye işlevleri, örtük tanım kötü biçimlendirildiğinde silinmiş olarak tanımlanır.

Bu özel üye işlevlerinden birini, tanımın gerekli olmadığı bir bağlamda (örneğin, potansiyel olarak değerlendirilmeyen bir açıklamada) kullanan geçerli bir C ++ 2003 programı, kötü biçimlendirilir.

Bana örnek:

struct A { private: A(); };
struct B : A { };
int main() { sizeof B(); /* valid in C++03, invalid in C++0x */ }

Bu tür hileler bazı SFINAE tarafından kullanıldı ve şimdi değiştirilmesi gerekiyor :)


Kullanıcı tarafından bildirilen yıkıcılar gizli bir istisna özelliğine sahiptir.

Bana örnek:

struct A {
  ~A() { throw "foo"; }
};

int main() { try { A a; } catch(...) { } }

Bu kod terminateC ++ 0x ile çağırır , ancak C ++ 03 ile çağırmaz. Çünkü A::~AC ++ 0x içinde örtülü istisna belirtimi noexcept(true).


exportC ++ 0x içinde geçerli bir C ++ 2003 bildirimi içeren kötü biçimlendirilmiş.


>Hemen ardından başka bir harf içeren geçerli bir C ++ 2003 ifadesi, >iki şablonun kapatılması olarak değerlendirilebilir.

C ++ 03'te >>her zaman vardiya operatörü belirteci olur.


Dahili bağlantılı işlevlerin bağımlı çağrılarına izin ver.

Bana örnek:

static void f(int) { }
void f(long) { }

template<typename T>
void g(T t) { f(t); }

int main() { g(0); }

C ++ 03'te bu çağırır f(long), ancak C ++ 0x'de bu çağırır f(int). Hem C ++ 03 hem de C ++ 0x'de aşağıdaki çağrıların f(B)(örnekleme bağlamının hala yalnızca dış bağlantı bildirimlerini dikkate aldığı) belirtilmesi gerekir.

struct B { };
struct A : B { };

template<typename T>
void g(T t) { f(t); }

static void f(A) { }
void f(B) { }

int main() { A a; g(a); }

f(A)Dış bağlantıya sahip olmadığı için daha iyi eşleşme alınmaz.


Kütüphane değişiklikleri

C ++ 0x'in C ++ standart kitaplığına eklenen tanımlayıcıları kullanan geçerli C ++ 2003 kodu, Bu Uluslararası Standartta farklı sonuçlar derleyemeyebilir veya üretemeyebilir.


#includesYeni C ++ 0x standart kitaplık başlıklarının adlarıyla üstbilgilerin geçerli geçerli C ++ 2003 kodu, bu Uluslararası Standartta geçersiz olabilir.


Takasın gerçekleşmesini beklerken derlenen geçerli C ++ 2003 kodunun <algorithm>aşağıdakileri içermesi gerekebilir<utility>


Global ad alanı posixartık standartlaştırma için ayrılmıştır.


Geçerli C ++ tanımlar o 2003 kod override, final, carries_dependency, veya noreturnmakro olarak C ++ 0x ile geçersiz.


Msgstr "Dahili bağlantılı fonksiyonların bağımlı çağrılarına izin ver." İki örneğiniz arasındaki farkı biraz açıklayabilir misiniz? Açıkça bir şey eksik.
Dennis Zickefoose

@ Değişiklik, open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#561 tarafından tanıtıldı . Bu durum hakkında yorum yapmasalar da, "örnekleme bağlamı" hala sadece "aynı çeviri biriminde şablon uzmanlığının somutlaştırılma noktasından önce beyan edilen dış bağlantıya sahip beyanlar kümesinden" oluşur. Böylece yaptıkları değişiklik sadece tanım bağlamındaki aramayı etkiler.
Johannes Schaub - litb

İlk örneğimde, iç bağlantı işlevi görünür ve şablonun tanım bağlamında bulundu. İkinci örneğimde, iç bağlantı işlevinin bulunacak örnekleme bağlamının bir parçası olması gerekir. Ama olmadığı için bulunamıyor.
Johannes Schaub - litb

Bu arada, bir şablon tanımı bağlamının iç bağlantıya sahip bir işlev bulmasının güvenli olduğu tek durumun, işlev şablonu uzmanlığının yalnızca bir TU'da (şablonun tanımlandığı yerde) açıkça somutlaştırılması ve diğer tüm TU'ların bu açık örnekleme. Diğer tüm durumlarda (diğer TU'ların uzmanlaşmayı kendilerinin başlatacağı yerlerde), şablon tanımının her seferinde farklı bir (iç bağlantı) işlevi kullanmasını sağlayarak ODR'yi ihlal edersiniz.
Johannes Schaub - litb

Dolayısıyla, neden örnekleme bağlamındaki kısıtlamayı koruduklarından emin değilim - yalnızca bir (açık) örnekleme olurdu ve bu örnekleme, örnekleme TU'sunun örnekleme bağlamında bulunan iç bağlantı işlevlerini kullanacaktır. Tıpkı tanım bağlamında olduğu gibi. Bu arada, eğer hala sahip olsaydık export, o zaman diğer TU'ların açık örneklemeye güvenmesi gerekmeyeceğini düşünüyorum , ancak şablonu kendileri başlatabilirlerdi. Ardından , iç bağlantı işlevlerinin örnekleme bağlamında görünür olup olmadığı bir fark yaratacaktır.
Johannes Schaub - litb

28

Otomatik anahtar kelimenin anlamı değişti.


9
autoAnahtar kelimeyi kullanıyorsanız, kodunuzla ilgili bir sorun var. Neden yeryüzünde kullanasýn ki?
Elazar Leibovich

Bu çok büyük bir değişiklik değil . Her geçerli C ++ 03 kullanımı autoC ++ 11'de geçerliliğini korur.
Drew Dormann

11
@DrewDormann int main() { auto int i = 0; return i; }mükemmel bir şekilde geçerli C ++ 03, ancak C ++ 11 sözdizimi hatası. C ++ 03 modunda derleyicilere verebileceğim tek uyarı uyumluluk hakkında bir uyarıdır.

24

Değişimi kırmak mı?

Eğer kullanılırsa Eh, bir şey için, decltype, constexpr, nullptr, vb tanımlayıcılar olarak o zaman sorun olabilir ...


21

Uyumsuzluklar bölümü kapsamında olmayan bazı temel uyumsuzluklar:


C ++ 0x, ad bir şablon şablonu parametresine bağımsız değişken olarak iletilirse, şablon türü parametresine iletilirse tür olarak enjekte edilen sınıf adını ele alır.

Geçerli C ++ 03 kodu, enjekte edilen sınıf adına bu senaryolarda her zaman bir tür olması gerektiğinde farklı davranabilir. Clang PR'ımdan alınan örnek kod

template<template<typename> class X>
struct M { };

template<template<typename> class X>
void g(int = 0); // #1

template<typename T>
void g(long = 0); // #2

template<typename T>
struct A {
  void f() {
    g<A>(); /* is ambiguous in C++0x */
    g<A>(1); /* should choose #1 in C++0x */
  }
};

void h() {
  A<int> a;
  a.f();
}

C ++ 03'te, kod gher ikisini de ikinci olarak çağırır .


C ++ 0x, C ++ 03 bağımlı olan bazı adları şimdi bağımlı olmayan yapar. Ayrıca, geçerli sınıf şablonunun üyelerine, örneklemede yinelenecek olan bağımlı olmayan nitelikli adlar için ad araması ve bu adların şablon tanımı bağlamında yapılanlarla aynı şekilde arandığını doğrulamayı gerektirir.

Hakimiyet kuralına bağlı geçerli C ++ 03 kodu artık bu değişiklik nedeniyle derlenmeyebilir.

Misal:

struct B { void f(); };

template<typename T>
struct A : virtual B { void f(); };

template<typename T>
struct C : virtual B, A<T> {
  void g() { this->f(); }
};

int main() { C<int> c; c.g(); }

Bu geçerli C ++ 03 kodu, A<int>::fC ++ 0x'de geçerli değildir, çünkü örnekleme sırasında ad araması A<int>::fbunun yerine B::f, tam tanım aramasıyla çakışmaya neden olur.

Bu noktada, bunun FDIS'te bir kusur olup olmadığı açık değildir. Komite bunun farkındadır ve durumu değerlendirecektir.


Son bölümün, bir temel sınıfı belirten niteleyicinin son bölümündeki niteleyicinin son bölümündeki tanımlayıcı ile aynı olduğu, bildirimin kullanılmasının artık bu ada sahip üyeler yerine yapıcıya ad verdiği kullanım bildirimi.

Misal:

struct A { protected: int B; };
typedef A B;

struct C : B {
  // inheriting constructor, instead of bringing A::B into scope
  using B::B;
};

int main() { C c; c.B = 0; }

Yukarıdaki örnek kod C ++ 03'te iyi biçimlendirilmiş, ancak A::Bhala erişilemediği gibi C ++ 0x'de kötü biçimlendirilmiş main.


14

Akış çıkarma hatası farklı şekilde ele alınır.

Misal

#include <sstream>
#include <cassert>

int main()
{
   std::stringstream ss;
   ss << '!';
   
   int x = -1;
   
   assert(!(ss >> x)); // C++03 and C++11
   assert(x == -1);    // C++03
   assert(x == 0);     // C++11
}

Teklifi değiştir

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3246.html#23

Standart referans

[C++03: 22.2.2.1.2/11]: Aşama 2 işlemenin sonucu,

  • Aşama 2'de (kurallarına göre scanf) türünün değerine dönüştürülen bir dizi karakter birikmiştir val. Bu değer içinde saklanır valve ios_base::goodbitiçinde saklanır err.
  • Aşama 2'de biriken karakter dizisi, scanfbir giriş arızasını rapor etmeye neden olurdu . ios_base::failbitatandı err. [ed: Hiçbir şey saklanmıyor val.]

[C++11: 22.4.2.1.2/3]: [..] Saklanacak sayısal değer şunlardan biri olabilir:

  • dönüştürme işlevi tüm alanı dönüştüremezse sıfır olur . ios_base::failbitatandı err.
  • alan temsil edilemeyecek kadar büyük bir değeri temsil ediyorsa, en pozitif temsil edilebilir değer val. ios_base::failbitatandı err.
  • alan gösterilemeyecek kadar büyük bir değeri temsil ediyorsa, işaretsiz bir tamsayı türü için temsili en negatif değer veya sıfır val. ios_base::failbitatandı err.
  • dönüştürülen değer, aksi takdirde.

Sonuçta elde edilen sayısal değer, içinde saklanır val.

Uygulamalar

  • GCC 4.8 , C ++ 11 için doğru çıktılar :

    `X == -1 'iddiası başarısız oldu

  • GCC 4.5-4.8 , C ++ 03 için tüm çıktılar , bir hata gibi görünecektir:

    `X == -1 'iddiası başarısız oldu

  • Visual C ++ 2008 Express , C ++ 03 için doğru çıktılar:

    Onaylama başarısız oldu: x == 0

  • Visual C ++ 2012 Express , uygulama durumu sorunu gibi görünen C ++ 11 için hatalı çıktılar:

    Onaylama başarısız oldu: x == 0


13

Açık dönüşüm operatörlerinin kullanılmaya başlaması nasıl kırıcı bir değişikliktir? Eski sürüm hala eskisi gibi "geçerli" olacaktır.

Evet, ' operator void*() constden explicit operator bool() constdeğişiklik kırıcı bir değişiklik olacaktır, ancak sadece kendi içinde ve dışında yanlış bir şekilde kullanılırsa. Uygun kod kırılmaz.

Şimdi, bir başka kırılma değişikliği, toplam başlatma sırasında dönüşümlerin daraltılmasının yasaklanması :

int a[] = { 1.0 }; // error

Düzenleme : Sadece hatırlatıcı, std::identity<T>C ++ 0x ile kaldırılacaktır (nota bakınız). Türleri bağımlı kılmak kolaylık sağlayan bir yapıdır. Yapı gerçekten fazla bir şey yapmadığından, bunu düzeltmelidir:

template<class T>
struct identity{
  typedef T type;
};

Standart kitaplık nesneleri açık dönüşümler eklediyse, mevcut örtülü dönüşümler çalışmayı durdurabilir. Ancak dönüşümün geçerli olmayacağı ve yararlı bir şey yapacağı bir senaryo hayal edemiyorum.
Dennis Zickefoose

Giriş o olacak çünkü bir kırma değişikliktir değiştirilmesi mevcut operator void*.
R. Martinho Fernandes

@Dennis: Aaah, şimdi @Martinho'nun ne anlama geldiğini anlıyorum. Ancak bu, yalnızca insanların amaçlanandan farklı bir şekilde kullanması durumunda kırıcı bir değişiklik olacaktır.
Xeo

"ama sadece kendi içinde ve dışında yanlış bir şekilde kullanılırsa" - bool ok = cin >> a; cout << "done reading" << endl; if (ok) { ... }C ++ 03 ile ilgili gerçekten yanlış bir şey yok, ama C ++ 11 bir hata haline gelmiştir. (Not: GCC 4.9 hala operator void*() constburadadır, bu yüzden kodu C ++ 11 modunda kabul eder.)

std::identity<T>C ++ 11'de kaldırılmadı, çünkü C ++ 03'ün bir parçası değildi. C ++ 11 için taslakta kısa bir süre vardı ve standardizasyondan önce taslaktan çıkarıldı.
Howard Hinnant


7

Geriye dönük uyumluluğu bozan örtülü hareket hakkında çok fazla tartışma var

( alakalı tartışma içeren eski bir sayfa )

Yorumları okuduysanız, örtülü taşıma dönüşü de önemli bir değişikliktir.


Bu tartışmaların sonucu, neredeyse tüm vakalarda kaldırılmasıdır. Geriye kalanlarla ilgili herhangi bir sorun var mı?
Dennis Zickefoose

@Dennis: Evet. Sorunuz zaten soruldu, cevaplandı ve bu takip sayfasında
Ben Voigt

Ahh, mobil sayfa yorumları göstermedi. Her iki durumda da, bu çok daha faydalı bir bağlantı ... Standardizasyon sürecinin tarihsel tuhaflıkları o kadar da önemli değil (MSVC kullanmıyorsanız, ilk taslağı kullandığına inanıyorum).
Dennis Zickefoose

@Dennis: Sanırım haklısın. Cevabımdaki bazı bağlantıları değiştirdim.
Ben Voigt

Ne yazık ki, cpp-next.com artık mevcut değil. İleride başvurmak üzere bunlar web.archive.org tarafından kaydedilen sayfalardır: örtük hareket geriye dönük uyumluluğu bozar ve ilgili tartışmalı daha eski bir sayfadır .
Max Truxa

6
struct x {
   x(int) {}
};

void f(auto x = 3) { }

int main() {
   f();
}

C ++ 03: geçerli.

C ++ 0x: error: parameter declared 'auto'


2
@ Xeo: Kod C ++ 03 için geçerlidir. Türlü struct xve adı olmayan bir parametredir .
Ben Voigt

Birisini yakalamayı umuyordum. Keşke @Xeo yorumunu silmek için o kadar hızlı olmasaydı, okumayı alamadım!
Orbit'te Hafiflik Yarışları

@ Xeo: Dilbilgisini araştırmadan, eminim auto sadece orada geçerli bir anahtar kelime değildir. Öyle olsaydı, muhtemelen beklediğiniz gibi çalışırdı, ancak muhtemelen doğru bir şekilde tanımlanması gerçekten zor.
Dennis Zickefoose

Sadece beni yakaladığını söyleyelim. Kelimenin tam anlamıyla yapıyı görmezden geldi. :)
Xeo

@Tomalek: Xeo haklı olarak C ++ 03'ün örtülü int'e sahip olmadığına dikkat çekmişti.
Ben Voigt

-4

Dil özellikleri

  1. {} Kullanarak tek tip ve genel başlatma
  2. Oto
  3. Daralmanın önlenmesi
  4. constexpr
  5. Döngü için aralık
  6. nullptr
  7. numaralandırma sınıfı
  8. static_assert
  9. std :: initializer_list
  10. Değer referansları (taşıma semantiği)
  11. >>
  12. Lambda'lar
  13. Değişken şablonları
  14. Tür ve şablon takma adları
  15. Unicode karakterler
  16. uzun uzun tamsayı tipi
  17. hizalama ve alignof
  18. decltype
  19. Ham dize değişmez değerleri
  20. Genelleştirilmiş POD
  21. Genelleştirilmiş sendikalar
  22. Şablon bağımsız değişkenleri olarak yerel sınıflar
  23. Sonek dönüş türü sözdizimi
  24. [[carries_dependency]] ve [[noreturn]]
  25. istisnasız belirleyici
  26. operatör hariç.
  27. C99 özellikleri:
    • genişletilmiş integral türleri
    • dar / geniş dize birleştirme
    • _ _ STDC_HOSTED _ _
    • _Pragma (X)
    • vararg makroları ve boş makro değişkenleri
  28. _ _ fonk _ _
  29. Satır içi ad alanları
  30. Kurucuları devretme
  31. Sınıf içi üye başlatıcıları
  32. varsayılan ve sil
  33. Açık dönüşüm operatörleri
  34. Kullanıcı tanımlı değişmez değerler
  35. Harici şablonlar
  36. İşlev şablonları için varsayılan şablon bağımsız değişkenleri
  37. Yapıcıları devralma
  38. geçersiz kıl ve son
  39. Daha basit ve daha genel SFINAE kuralı
  40. Bellek modeli
  41. thread_local

Standart Kütüphane Bileşenleri

  1. kapsayıcılar için initializer_list
  2. Kapsayıcılar için anlambilimi taşıma
  3. forward_list
  4. Karma kaplar
    • unordered_map
    • unordered_multimap
    • unordered_set
    • unordered_multiset
  5. Kaynak yönetimi işaretçileri
    • unique_ptr
    • shared_ptr
    • weak_ptr
  6. Eşzamanlılık desteği
    • Konu
    • muteksler
    • kilitleri
    • koşul değişkenleri
  7. Üst düzey eşzamanlılık desteği
    • packaged_thread
    • gelecek
    • söz vermek
    • zaman uyumsuz
  8. Tuplelerin
  9. regex
  10. Rastgele sayılar
    • uniform_int_distribution
    • normal dağılım
    • random_engine
    • vb.
  11. İnt16_t, uint32_t ve int_fast64_t gibi tamsayı türü adları
  12. dizi
  13. İstisnaları kopyalama ve yeniden bağlama
  14. Sistem hatası
  15. konteynerler için emplace () işlemleri
  16. constexpr fonksiyonları
  17. Harici fonksiyonların sistematik kullanımı
  18. işlev ve bağlama
  19. Dize - sayısal değer dönüşümleri
  20. Kapsamlı ayırıcılar
  21. Tip özellikleri
  22. Zaman yardımcı programları: süre ve zaman_ noktası
  23. oran
  24. quick_exit
  25. Move (), copy_if () ve is_sorted () gibi daha fazla algoritma
  26. Çöp toplama ABI
  27. nükleer fizik

Kullanımdan Kaldırılan Özellikler

  1. Bir yıkıcı içeren bir sınıf için kopya yapıcısının ve kopya atamasının oluşturulması.
  2. Bir karakter * için bir dize değişmez değeri atayın.
  3. C ++ 98 kural dışı durum belirtimi
    • unexcepted_handler
    • set_unexpected
    • get_unexpected
    • beklenmedik
  4. İşlev nesneleri ve ilişkili işlevler
  5. auto_ptr
  6. Kayıt ol
  7. ++ bir bool üzerinde
  8. ihracat
  9. C tarzı dökümler

3
Bu soruya cevap vermiyor.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.