Perubahan apa yang diperkenalkan pada C ++ 11?

227

Saya tahu bahwa setidaknya salah satu perubahan dalam C ++ 11 yang akan menyebabkan beberapa kode lama berhenti dikompilasi: pengenalan explicit operator bool()di perpustakaan standar, menggantikan contoh lama dari operator void*(). Memang, kode yang akan dipecah ini mungkin kode yang seharusnya tidak valid di tempat pertama, tetapi tetap saja merupakan perubahan besar: program yang dulu valid tidak lagi.

Apakah ada perubahan melanggar lainnya?

R. Martinho Fernandes
sumber
1
Menghapus makna exportkata kunci? Saya akan memberi saya mantel.
Steve Jessop
7
Anda tahu, saya tidak akan menyebutnya perubahan konversi menjadi "perubahan melanggar" ... lebih seperti "perubahan hukuman".
Xeo
4
Ketika semua dokumen yang diperlukan untuk membuat serikat seperti itu hanya menunggu untuk distempel, tentu saja, mengapa tidak?
Dennis Zickefoose
3
@ Xeo: mystream.good()tidak sama dengan bool(mystream)? good()benar jika tidak ada bendera yang ditetapkan. bool(mystream)masih salah jika hanya eofbitdisetel. !mystream.fail()akan menjadi setara yang benar.
R. Martinho Fernandes
2
Catatan Moderator : " Tolong simpan komentar pada topik dengan pertanyaan atau jawaban. Saat membahas pertanyaan atau jawaban, diskusi harus tentang hal itu, pertanyaan atau jawaban yang ada. Berdebat, secara umum tidak konstruktif untuk Stack Overflow. Antagonisasi tentu saja tidak. "
Tim Post

Jawaban:

178

FDIS memiliki bagian untuk ketidakcocokan, pada lampiran C.2"C ++ dan ISO C ++ 2003".

Ringkasan, memparafrasekan FDIS di sini, untuk membuatnya (lebih baik) cocok sebagai jawaban SO. Saya menambahkan beberapa contoh saya sendiri untuk menggambarkan perbedaan.

Ada beberapa ketidakcocokan yang berhubungan dengan perpustakaan di mana saya tidak tahu persis implikasinya, jadi saya meninggalkannya untuk diuraikan oleh orang lain.

Bahasa inti


#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 .

Kata kunci baru: alignas, alignof, char16_t, char32_t, constexpr, decltype, noexcept, nullptr, static_assert, dan thread_local


Literer integer tertentu yang lebih besar dari yang dapat diwakili oleh long dapat berubah dari tipe integer yang tidak ditandatangani menjadi lama yang ditandatangani.


Kode C ++ 2003 yang valid yang menggunakan pembulatan bilangan bulat bulat hasilnya ke 0 atau ke arah infinity negatif, sedangkan C ++ 0x selalu membulatkan hasilnya ke 0.

(diakui bukan masalah kompatibilitas bagi kebanyakan orang).


Kode C ++ 2003 yang valid yang menggunakan kata kunci autosebagai specifier kelas penyimpanan mungkin tidak valid dalam C ++ 0x.


Konversi yang sempit menyebabkan ketidakcocokan dengan C ++ 03. Misalnya, kode berikut ini valid dalam C ++ 2003 tetapi tidak valid dalam Standar Internasional ini karena double to int adalah konversi yang menyempit:

int x[] = { 2.0 };

Fungsi anggota khusus yang dideklarasikan secara implisit didefinisikan sebagai dihapus ketika definisi implisit akan telah dibentuk dengan buruk.

Program C ++ 2003 yang valid yang menggunakan salah satu fungsi anggota khusus ini dalam konteks di mana definisi tidak diperlukan (misalnya, dalam ekspresi yang tidak berpotensi dievaluasi) menjadi salah bentuk.

Contoh oleh saya:

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

Trik sizeof seperti itu telah digunakan oleh beberapa SFINAE, dan perlu diubah sekarang :)


Destroyer yang dideklarasikan pengguna memiliki spesifikasi pengecualian implisit.

Contoh oleh saya:

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

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

Kode ini memanggil terminateC ++ 0x, tetapi tidak di C ++ 03. Karena spesifikasi pengecualian implisit A::~Adalam C ++ 0x adalah noexcept(true).


Deklarasi C ++ 2003 yang valid yang berisi exportsalah bentuk dalam C ++ 0x.


Ekspresi C ++ 2003 yang valid berisi >diikuti segera oleh yang lain >sekarang dapat dianggap sebagai penutupan dua templat.

Dalam C ++ 03, >>akan selalu menjadi token operator-shift.


Izinkan panggilan fungsi yang bergantung dengan tautan internal.

Contoh oleh saya:

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

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

int main() { g(0); }

Di C ++ 03, ini panggilan f(long), tetapi di C ++ 0x, ini panggilan f(int). Perlu dicatat bahwa di C ++ 03 dan C ++ 0x, panggilan berikut f(B)(konteks instantiasi masih hanya mempertimbangkan deklarasi linkage eksternal).

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); }

Pencocokan yang lebih baik f(A)tidak diambil, karena tidak memiliki tautan eksternal.


Perubahan perpustakaan

Kode C ++ 2003 yang valid yang menggunakan pengidentifikasi apa pun yang ditambahkan ke pustaka standar C ++ dari C ++ 0x mungkin gagal untuk mengkompilasi atau menghasilkan hasil yang berbeda dalam Standar Internasional ini.


Kode C ++ 2003 yang valid yang #includestajuk dengan nama header pustaka standar C ++ 0x yang baru mungkin tidak valid dalam Standar Internasional ini.


Kode C ++ 2003 yang valid yang telah dikompilasi mengharapkan swap menjadi <algorithm>mungkin harus dimasukkan<utility>


Ruang nama global posixsekarang dicadangkan untuk standardisasi.


Hari C ++ 2003 kode yang mendefinisikan override, final, carries_dependency, atau noreturnsebagai macro tidak valid di C ++ 0x.

Johannes Schaub - litb
sumber
"Izinkan panggilan fungsi yang bergantung dengan tautan internal." Bisakah Anda jelaskan perbedaan antara dua contoh Anda? Saya jelas melewatkan sesuatu.
Dennis Zickefoose
@Dennis perubahan itu diperkenalkan oleh open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#561 . Meskipun mereka tidak mengomentari fakta tersebut, "konteks instantiasi" masih terdiri dari hanya "set deklarasi dengan tautan eksternal yang dideklarasikan sebelum titik instantiasi spesialisasi templat di unit terjemahan yang sama". Jadi perubahan yang mereka buat hanya memengaruhi pencarian dalam konteks definisi.
Johannes Schaub - litb
Dalam contoh pertama yang saya berikan, fungsi tautan internal terlihat dan ditemukan dalam konteks definisi template. Dalam contoh kedua saya, fungsi tautan internal perlu menjadi bagian dari konteks instantiation yang ditemukan. Tetapi karena tidak, itu tidak dapat ditemukan.
Johannes Schaub - litb
Kebetulan, saya pikir satu-satunya kasus di mana aman untuk konteks definisi templat untuk menemukan fungsi dengan tautan internal adalah ketika spesialisasi templat fungsi hanya secara instantiated secara instantiated dalam satu TU (di mana templat didefinisikan), dan semua TU lain bergantung pada Instansiasi eksplisit itu. Dalam semua kasus lain (di mana TU lain akan instantiate spesialisasi itu sendiri), Anda akan melanggar ODR dengan meminta definisi template menggunakan fungsi (hubungan internal) yang berbeda setiap kali.
Johannes Schaub - litb
Jadi saya tidak yakin mengapa mereka menahan batasan pada konteks instantiasi - hanya akan ada satu instantiasi (eksplisit), dan instantiasi itu akan menggunakan fungsi tautan internal yang ditemukan dalam konteks instantiasi TU instantiasi. Persis seperti itu untuk konteks definisi. Kebetulan, saya pikir jika kita masih memiliki export, maka saya pikir TU lain tidak perlu bergantung pada instantiasi eksplisit, tetapi bisa instantiate template itu sendiri. Maka akan membuat perbedaan apakah fungsi tautan internal terlihat dalam konteks instantiation.
Johannes Schaub - litb
28

Arti kata kunci otomatis berubah.

arsenm
sumber
9
Jika Anda menggunakan autokata kunci, ada yang salah dengan kode Anda. Kenapa Anda akan menggunakannya?
Elazar Leibovich
Itu bukan perubahan yang berarti . Setiap penggunaan C ++ 03 yang autovalid tetap valid di C ++ 11.
Drew Dormann
11
@DrewDormann int main() { auto int i = 0; return i; }benar-benar valid C ++ 03, tetapi kesalahan sintaksis dalam C ++ 11 Satu-satunya peringatan yang bisa saya dapatkan dari kompiler adalah dalam mode C ++ 03 adalah peringatan tentang kompatibilitas.
24

Melanggar perubahan?

Nah, untuk satu hal, jika Anda menggunakan decltype, constexpr, nullptr, dll sebagai pengidentifikasi maka Anda mungkin berada dalam kesulitan ...

Downvoter
sumber
21

Beberapa ketidakcocokan inti yang tidak tercakup oleh bagian ketidakcocokan:


C ++ 0x memperlakukan nama kelas yang disuntikkan sebagai templat, jika nama dilewatkan sebagai argumen ke parameter templat templat, dan sebagai jenis jika dilewatkan ke parameter jenis templat.

Kode C ++ 03 yang valid dapat berperilaku berbeda jika bergantung pada nama kelas yang disuntikkan untuk selalu menjadi tipe dalam skenario ini. Contoh kode diambil dari PR dentang saya

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();
}

Dalam C ++ 03, kode memanggil yang kedua gkali.


C ++ 0x membuat beberapa nama yang bergantung pada C ++ 03 menjadi sekarang tidak tergantung. Dan memerlukan pencarian nama untuk nama-nama terkualifikasi yang tidak bergantung yang merujuk kepada anggota templat kelas saat ini untuk diulangi saat instantiasi, dan memerlukan verifikasi bahwa nama-nama ini mencari dengan cara yang sama seperti yang dilakukan pada konteks definisi templat.

Kode C ++ 03 yang valid yang bergantung pada aturan dominasi sekarang tidak dapat dikompilasi lagi karena perubahan ini.

Contoh:

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(); }

Kode C ++ 03 ini valid yang memanggil A<int>::ftidak valid dalam C ++ 0x, karena pencarian nama ketika instantiating akan menemukan A<int>::fbertentangan B::f, menyebabkan konflik dengan pencarian definisi-at.

Pada titik ini, tidak jelas apakah itu cacat dalam FDIS. Panitia mengetahui hal ini dan akan mengevaluasi situasinya.


Deklarasi menggunakan di mana bagian terakhir sama dengan pengidentifikasi di bagian terakhir kualifikasi di nama yang memenuhi syarat yang menunjukkan kelas dasar, yang menggunakan deklarasi sekarang nama konstruktor, bukan anggota dengan nama itu.

Contoh:

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; }

Kode contoh di atas terbentuk dengan baik di C ++ 03, tetapi tidak terbentuk dengan baik di C ++ 0x, karena A::Bmasih tidak dapat diakses di main.

Johannes Schaub - litb
sumber
14

Kegagalan ekstraksi aliran diperlakukan secara berbeda.

Contoh

#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
}

Ubah proposal

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

Referensi standar

[C++03: 22.2.2.1.2/11]: Hasil dari pemrosesan tahap 2 dapat menjadi salah satunya

  • Urutan karakter telah diakumulasikan pada tahap 2 yang dikonversi (sesuai aturan scanf) ke nilai tipe val. Nilai ini disimpan di valdan ios_base::goodbitdisimpan di err.
  • Urutan karakter yang terakumulasi pada tahap 2 akan menyebabkan scanfmelaporkan kegagalan input. ios_base::failbitditugaskan untuk err. [ed: Tidak ada yang disimpan val.]

[C++11: 22.4.2.1.2/3]: [..] Nilai numerik yang akan disimpan dapat berupa:

  • nol, jika fungsi konversi gagal untuk mengonversi seluruh bidang . ios_base::failbitditugaskan untuk err.
  • nilai keterwakilan paling positif, jika bidang mewakili nilai terlalu besar untuk diwakili dalam val. ios_base::failbitditugaskan untuk err.
  • nilai keterwakilan paling negatif atau nol untuk tipe bilangan bulat yang tidak ditandatangani, jika bidang mewakili nilai yang terlalu besar untuk diwakili dalam val. ios_base::failbitditugaskan untuk err.
  • nilai yang dikonversi, jika tidak.

Nilai numerik yang dihasilkan disimpan di val.

Implementasi

  • GCC 4.8 mengeluarkan dengan benar untuk C ++ 11 :

    Pernyataan `x == -1 'gagal

  • GCC 4.5-4.8 semua output untuk C ++ 03 berikut ini, yang akan muncul sebagai bug:

    Pernyataan `x == -1 'gagal

  • Visual C ++ 2008 Express menampilkan dengan benar untuk C ++ 03:

    Pernyataan gagal: x == 0

  • Visual C ++ 2012 Express salah output untuk C ++ 11, yang akan muncul menjadi masalah status implementasi:

    Pernyataan gagal: x == 0

Lightness Races di Orbit
sumber
13

Bagaimana pengenalan operator konversi eksplisit merupakan perubahan besar? Versi lama akan tetap "valid" seperti sebelumnya.

Ya, perubahan dari operator void*() constke explicit operator bool() constakan menjadi perubahan melanggar, tetapi hanya jika digunakan dengan cara yang salah dan keluar dari dirinya sendiri. Kode yang sesuai tidak akan rusak.

Sekarang, perubahan lain yang melanggar adalah pelarangan penyempitan konversi selama inisialisasi agregat :

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

Sunting : Hanya pengingat, std::identity<T>akan dihapus dalam C ++ 0x (lihat catatan). Ini adalah struct kenyamanan untuk membuat tipe tergantung. Karena struct benar-benar tidak berbuat banyak, ini harus memperbaikinya:

template<class T>
struct identity{
  typedef T type;
};
Xeo
sumber
Jika objek pustaka standar memiliki konversi eksplisit yang ditambahkan, maka konversi implisit yang ada dapat berhenti berfungsi. Tetapi saya tidak dapat membayangkan skenario di mana konversi tidak akan valid dan melakukan sesuatu yang bermanfaat.
Dennis Zickefoose
Pendahuluan adalah perubahan besar karena ini akan menggantikan yang sudah ada operator void*.
R. Martinho Fernandes
@ Dennis: Aaah, saya mengerti sekarang apa yang dimaksud @Martinho. Tapi itu hanya akan menjadi perubahan besar jika orang menggunakannya selain yang dimaksudkan.
Xeo
"tetapi hanya jika digunakan dengan cara yang salah masuk dan keluar dari dirinya sendiri" - bool ok = cin >> a; cout << "done reading" << endl; if (ok) { ... }Tidak ada yang benar-benar salah dengan itu di C ++ 03, namun itu telah menjadi kesalahan di C ++ 11. (Catatan: GCC 4.9 masih ada di operator void*() constsini, itulah sebabnya mengapa ia menerima kode dalam mode C ++ 11.)
std::identity<T>tidak dihapus di C ++ 11, karena itu bukan bagian dari C ++ 03. Itu memang ada sebentar di draft untuk C ++ 11, dan telah dihapus dari draft sebelum standarisasi.
Howard Hinnant
7

Sudah ada banyak diskusi tentang langkah implisit yang melanggar kompatibilitas

( halaman yang lebih tua dengan diskusi yang relevan )

Jika Anda membaca komentar, pemindahan implisit juga merupakan perubahan besar.

Ben Voigt
sumber
Hasil dari diskusi itu adalah bahwa ia dihapus di hampir semua kasus. Apakah ada masalah dengan apa yang tersisa?
Dennis Zickefoose
@ Dennis: Ya. Pertanyaan Anda sudah diajukan, dijawab, dan diperdebatkan sampai mati pada halaman tindak lanjut ini
Ben Voigt
Ahh, halaman seluler tidak menunjukkan komentar. Apa pun itu, itu tautan yang jauh lebih berguna ... Keanehan historis dari proses standardisasi tidak relevan (kecuali jika Anda menggunakan MSVC, yang saya percaya menggunakan konsep pertama).
Dennis Zickefoose
@ Dennis: Saya pikir Anda benar. Memindahkan tautan di beberapa jawaban saya.
Ben Voigt
Sayangnya, cpp-next.com tidak ada lagi. Untuk referensi di masa mendatang, ini adalah halaman yang disimpan oleh web.archive.org: langkah tersirat yang melanggar kompatibilitas mundur dan halaman yang lebih tua dengan diskusi yang relevan .
Max Truxa
6
struct x {
   x(int) {}
};

void f(auto x = 3) { }

int main() {
   f();
}

C ++ 03: valid.

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

Lightness Races di Orbit
sumber
2
@Xeo: Kode ini valid dalam C ++ 03. Ini adalah parameter dengan tipe struct xdan tanpa nama.
Ben Voigt
Saya berharap untuk menangkap seseorang. Saya hanya berharap @Xeo tidak begitu cepat untuk menghapus komentarnya, karena saya tidak bisa membacanya!
Lightness Races in Orbit
@ Xeo: Tanpa menggali tata bahasa, saya yakin otomatis tidak ada kata kunci yang valid di sana. Jika ya, itu mungkin akan berfungsi seperti yang Anda harapkan, tapi itu mungkin sangat sulit untuk didefinisikan dengan benar.
Dennis Zickefoose
Anggap saja Anda menangkap saya. Ini benar-benar mengabaikan struct. :)
Xeo
@ Tomalek: Xeo dengan tepat menunjukkan bahwa C ++ 03 tidak memiliki int implisit.
Ben Voigt
-4

Fitur Bahasa

  1. Inisialisasi seragam dan umum menggunakan {}
  2. mobil
  3. Pencegahan penyempitan
  4. constexpr
  5. Rentang berdasarkan untuk loop
  6. nullptr
  7. kelas enum
  8. static_assert
  9. std :: initializer_list
  10. Nilai referensi (pindahkan semantik)
  11. >>
  12. Lambdas
  13. Templat variadik
  14. Ketik dan templat alias
  15. Karakter Unicode
  16. tipe integer panjang panjang
  17. menyelaraskan dan menyelaraskan
  18. menyatakan jenis
  19. Literal string mentah
  20. POD umum
  21. Serikat pekerja umum
  22. Kelas lokal sebagai argumen templat
  23. Sintaks tipe suffix return
  24. [[carries_dependency]] dan [[noreturn]]
  25. noexcept specifier
  26. operator tidak terkecuali.
  27. Fitur C99:
    • tipe integral yang diperluas
    • penggabungan string sempit / lebar
    • _ _ STDC_HOSTED _ _
    • _Pragma (X)
    • makro vararg dan argumen makro kosong
  28. _ _ func _ _
  29. Ruang nama sebaris
  30. Mendelegasikan konstruktor
  31. Inisialisasi anggota di dalam kelas
  32. default dan hapus
  33. Operator konversi eksplisit
  34. Literal yang ditentukan pengguna
  35. Templat eksternal
  36. Argumen templat default untuk templat fungsi
  37. Warisan konstruktor
  38. timpa dan final
  39. Aturan SFINAE yang lebih sederhana dan lebih umum
  40. Model memori
  41. thread_local

Komponen Perpustakaan Standar

  1. initializer_list untuk wadah
  2. Pindahkan semantik untuk wadah
  3. forward_list
  4. Kontainer hash
    • unordered_map
    • unordered_multimap
    • unordered_set
    • unordered_multiset
  5. Petunjuk pengelolaan sumber daya
    • unique_ptr
    • shared_ptr
    • lemah_ptr
  6. Dukungan konkurensi
    • benang
    • mutex
    • kunci
    • variabel kondisi
  7. Dukungan konkurensi tingkat tinggi
    • packaged_thread
    • masa depan
    • janji
    • async
  8. tupel
  9. regex
  10. Angka acak
    • uniform_int_distribution
    • distribusi normal
    • random_engine
    • dll.
  11. Nama tipe integer, seperti int16_t, uint32_t, dan int_fast64_t
  12. Himpunan
  13. Menyalin dan memikirkan kembali pengecualian
  14. sistem bermasalah
  15. emplace () operasi untuk kontainer
  16. fungsi constexpr
  17. Penggunaan sistematis fungsi-fungsi noexcept
  18. berfungsi dan mengikat
  19. String ke konversi nilai numerik
  20. Alokasi pengalokasi
  21. Ketik ciri
  22. Utilitas waktu: durasi dan titik waktu
  23. perbandingan
  24. quick_exit
  25. Lebih banyak algoritma, seperti move (), copy_if (), dan is_sorted ()
  26. Pengumpulan sampah ABI
  27. atom

Fitur usang

  1. Pembuatan copy constructor dan penugasan copy untuk kelas dengan destructor.
  2. Tetapkan string literal ke char *.
  3. C ++ 98 spesifikasi pengecualian
    • unexcepted_handler
    • set_unexpected
    • get_unexpected
    • tak terduga
  4. Fungsi objek dan fungsi terkait
  5. auto_ptr
  6. daftar
  7. ++ pada bool
  8. ekspor
  9. Gips gaya-C
mustafagonul
sumber
3
Ini tidak menjawab pertanyaan.