Ya, ada sejumlah perubahan yang akan menyebabkan kode yang sama menghasilkan perilaku yang berbeda antara C ++ 03 dan C ++ 11. Perbedaan aturan sekuensing membuat beberapa perubahan menarik termasuk beberapa perilaku yang sebelumnya tidak terdefinisi menjadi didefinisikan dengan baik.
1. beberapa mutasi dari variabel yang sama dalam daftar penginisialisasi
Satu kasus sudut yang sangat menarik adalah banyak mutasi dari variabel yang sama dalam daftar penginisialisasi, misalnya:
int main()
{
int count = 0 ;
int arrInt[2] = { count++, count++ } ;
return 0 ;
}
Baik dalam C ++ 03 dan C ++ 11 ini didefinisikan dengan baik tetapi urutan evaluasi dalam C ++ 03 tidak ditentukan tetapi dalam C ++ 11 mereka dievaluasi dalam urutan di mana mereka muncul . Jadi jika kita mengkompilasi menggunakan clang
dalam mode C ++ 03 itu memberikan peringatan berikut ( lihat langsung ):
warning: multiple unsequenced modifications to 'count' [-Wunsequenced]
int arrInt[2] = { count++, count++ } ;
^ ~~
tetapi tidak memberikan peringatan di C ++ 11 ( lihat langsung ).
2. Aturan sekuensing baru membuat i = ++ i +1; didefinisikan dengan baik dalam C ++ 11
Aturan pengurutan baru yang diadopsi setelah C ++ 03 berarti bahwa:
int i = 0 ;
i = ++ i + 1;
tidak lagi perilaku tidak terdefinisi dalam C ++ 11, ini tercakup dalam laporan cacat 637. Aturan pengurutan dan contoh tidak setuju
3. Aturan pengurutan baru juga membuat ++++ i; didefinisikan dengan baik dalam C ++ 11
Aturan pengurutan baru yang diadopsi setelah C ++ 03 berarti bahwa:
int i = 0 ;
++++i ;
tidak lagi perilaku tidak terdefinisi dalam C ++ 11.
4. Sedikit Lebih Masuk Akal Tertanda-Kiri
Konsep selanjutnya dari C ++ 11 termasuk N3485
yang saya tautkan di bawah ini memperbaiki perilaku yang tidak terdefinisi yaitu menggeser 1 bit menjadi atau melewati bit tanda . Ini juga tercakup dalam laporan cacat 1457 . Howard Hinnant mengomentari pentingnya perubahan pada utas tentang Apakah kiri-bergeser (<<) bilangan bulat negatif perilaku tidak terdefinisi dalam C ++ 11? .
5. fungsi constexpr dapat diperlakukan sebagai kompilasi ekspresi konstanta waktu dalam C ++ 11
C ++ 11 memperkenalkan fungsi constexpr yang:
Specifier constexpr menyatakan bahwa adalah mungkin untuk mengevaluasi nilai fungsi atau variabel pada waktu kompilasi. Variabel dan fungsi tersebut kemudian dapat digunakan di mana hanya kompilasi ekspresi konstan waktu yang diizinkan.
sementara C ++ 03 tidak memiliki fitur constexpr , kami tidak perlu menggunakan kata kunci constexpr secara eksplisit karena pustaka standar menyediakan banyak fungsi di C ++ 11 sebagai constexpr . Misalnya std :: numeric_limits :: min . Yang dapat menyebabkan perilaku berbeda, misalnya:
#include <limits>
int main()
{
int x[std::numeric_limits<unsigned int>::min()+2] ;
}
Menggunakan clang
dalam C ++ 03 ini akan menyebabkan x
array panjang variabel, yang merupakan ekstensi dan akan menghasilkan peringatan berikut:
warning: variable length arrays are a C99 feature [-Wvla-extension]
int x[std::numeric_limits<unsigned int>::min()+2] ;
^
sedangkan di C ++ 11 std::numeric_limits<unsigned int>::min()+2
adalah ekspresi konstanta waktu kompilasi dan tidak memerlukan ekstensi VLA.
6. Dalam C ++ 11 spesifikasi pengecualian noexcept secara implisit dihasilkan untuk destruktor Anda
Karena dalam C ++ 11 destruktor yang ditentukan pengguna memiliki noexcept(true)
spesifikasi implisit seperti yang dijelaskan dalam destruktor noexcept itu berarti bahwa program berikut:
#include <iostream>
#include <stdexcept>
struct S
{
~S() { throw std::runtime_error(""); } // bad, but acceptable
};
int main()
{
try { S s; }
catch (...) {
std::cerr << "exception occurred";
}
std::cout << "success";
}
Di C ++ 11 akan memanggil std::terminate
tetapi akan berhasil dijalankan di C ++ 03.
7. Dalam C ++ 03, argumen templat tidak dapat memiliki tautan internal
Ini tercakup dengan baik di Mengapa std :: sort tidak menerima kelas Bandingkan dideklarasikan dalam suatu fungsi . Jadi kode berikut seharusnya tidak berfungsi di C ++ 03:
#include <iostream>
#include <vector>
#include <algorithm>
class Comparators
{
public:
bool operator()(int first, int second)
{
return first < second;
}
};
int main()
{
class ComparatorsInner : public Comparators{};
std::vector<int> compares ;
compares.push_back(20) ;
compares.push_back(10) ;
compares.push_back(30) ;
ComparatorsInner comparatorInner;
std::sort(compares.begin(), compares.end(), comparatorInner);
std::vector<int>::iterator it;
for(it = compares.begin(); it != compares.end(); ++it)
{
std::cout << (*it) << std::endl;
}
}
tetapi saat clang
ini memungkinkan kode ini dalam mode C ++ 03 dengan peringatan kecuali Anda menggunakan -pedantic-errors
flag, yang agak menjijikkan, lihat langsung .
8. >> tidak lagi salah bentuk saat menutup beberapa templat
Menggunakan >>
untuk menutup beberapa templat tidak lagi salah bentuk tetapi dapat menyebabkan kode dengan hasil berbeda di C ++ 03 dan C + 11. Contoh di bawah ini diambil dari kurung siku kanan dan kompatibilitas ke belakang :
#include <iostream>
template<int I> struct X {
static int const c = 2;
};
template<> struct X<0> {
typedef int c;
};
template<typename T> struct Y {
static int const c = 3;
};
static int const c = 4;
int main() {
std::cout << (Y<X<1> >::c >::c>::c) << '\n';
std::cout << (Y<X< 1>>::c >::c>::c) << '\n';
}
dan hasilnya dalam C ++ 03 adalah:
0
3
dan di C ++ 11:
0
0
9. C ++ 11 mengubah beberapa konstruktor std :: vector
Kode yang sedikit dimodifikasi dari jawaban ini menunjukkan bahwa menggunakan konstruktor berikut dari std :: vector :
std::vector<T> test(1);
menghasilkan hasil yang berbeda di C ++ 03 dan C ++ 11:
#include <iostream>
#include <vector>
struct T
{
bool flag;
T() : flag(false) {}
T(const T&) : flag(true) {}
};
int main()
{
std::vector<T> test(1);
bool is_cpp11 = !test[0].flag;
std::cout << is_cpp11 << std::endl ;
}
10. Persempit konversi dalam inisialisasi agregat
Dalam C ++ 11 konversi penyempitan dalam inisialisasi agregat tidak terbentuk dan sepertinya gcc
memungkinkan ini di C ++ 11 dan C ++ 03 meskipun itu memberikan peringatan secara default di C ++ 11:
int x[] = { 2.0 };
Ini dicakup dalam draft C ++ 11 bagian standar 8.5.4
Daftar-inisialisasi paragraf 3 :
Daftar-inisialisasi objek atau referensi tipe T didefinisikan sebagai berikut:
dan mengandung peluru berikut ( penekanan milikku ):
Kalau tidak, jika T adalah tipe kelas, konstruktor dianggap. Konstruktor yang berlaku disebutkan dan yang terbaik dipilih melalui resolusi kelebihan beban (13.3, 13.3.1.7). Jika konversi penyempitan (lihat di bawah) diperlukan untuk mengonversi salah satu argumen, program ini salah bentuk
Ini dan banyak lagi contoh dibahas dalam rancangan C ++ bagian standar annex C.2
C ++ dan ISO C ++ 2003 . Ini juga termasuk:
Jenis baru string literal [...] Secara khusus, makro bernama R, u8, u8R, u, uR, U, UR, atau LR tidak akan diperluas ketika berdekatan dengan string literal tetapi akan ditafsirkan sebagai bagian dari string literal . Sebagai contoh
#define u8 "abc"
const char *s = u8"def"; // Previously "abcdef", now "def"
Dukungan string literal yang ditentukan pengguna [...] Sebelumnya, # 1 akan terdiri dari dua token pemroses yang terpisah dan makro _x akan diperluas. Dalam Standar Internasional ini, # 1 terdiri dari satu token pemrosesan awal, sehingga makro tidak diperluas.
#define _x "there"
"hello"_x // #1
Tentukan pembulatan untuk hasil bilangan bulat / dan% [...] kode 2003 yang menggunakan pembulatan bilangan bulat bulat hasilnya ke 0 atau ke arah infinity negatif, sedangkan Standar Internasional ini selalu membulatkan hasilnya ke 0.
Kompleksitas ukuran () fungsi anggota sekarang konstan [...] Beberapa implementasi wadah yang sesuai dengan C ++ 2003 mungkin tidak sesuai dengan persyaratan ukuran yang ditentukan () dalam Standar Internasional ini. Menyesuaikan wadah seperti std :: list dengan persyaratan yang lebih ketat mungkin memerlukan perubahan yang tidak kompatibel.
Ubah kelas dasar std :: ios_base :: failure [...] std :: ios_base :: failure tidak lagi diturunkan langsung dari std :: exception, tetapi sekarang berasal dari std :: system_error, yang pada gilirannya berasal dari std :: runtime_error. Kode C ++ 2003 yang valid yang mengasumsikan bahwa std :: ios_base :: failure diturunkan langsung dari std :: exception dapat dieksekusi secara berbeda dalam Standar Internasional ini.
auto
dapat menghasilkan situasi seperti ini