ใช่มีจำนวนการเปลี่ยนแปลงที่จะทำให้รหัสเดียวกันส่งผลให้เกิดพฤติกรรมที่แตกต่างกันระหว่าง C ++ 03 และ C ++ 11 ความแตกต่างของกฎการจัดลำดับทำให้เกิดการเปลี่ยนแปลงที่น่าสนใจรวมถึงพฤติกรรมบางอย่างที่ไม่ได้กำหนดไว้ก่อนหน้านี้ซึ่งได้กำหนดไว้อย่างดี
1. การกลายพันธุ์ของตัวแปรเดียวกันหลายรายการภายในรายการ initializer
กรณีมุมที่น่าสนใจมากอย่างหนึ่งจะกลายพันธุ์ของตัวแปรเดียวกันหลายรายการภายในรายการ initializer ตัวอย่างเช่น:
int main()
{
int count = 0 ;
int arrInt[2] = { count++, count++ } ;
return 0 ;
}
ทั้งใน C ++ 03 และ C ++ 11 นี้ถูกกำหนดไว้อย่างดี แต่คำสั่งของการประเมินผลใน C ++ 03 ไม่ได้ระบุแต่ในC ++ 11 พวกเขาได้รับการประเมินในลำดับที่ปรากฏ ดังนั้นถ้าเราคอมไพล์โดยใช้clang
ในโหมด C ++ 03 มันให้คำเตือนต่อไปนี้ ( ดูสด ):
warning: multiple unsequenced modifications to 'count' [-Wunsequenced]
int arrInt[2] = { count++, count++ } ;
^ ~~
แต่ไม่ได้ให้คำเตือนใน C ++ 11 ( ดูแบบสด )
2. กฎการเรียงลำดับใหม่ทำให้ i = ++ i + 1; กำหนดไว้อย่างดีใน C ++ 11
กฎการเรียงลำดับใหม่ที่ใช้หลังจาก C ++ 03 หมายความว่า:
int i = 0 ;
i = ++ i + 1;
ไม่มีพฤติกรรมที่ไม่ได้กำหนดใน C ++ 11 อีกต่อไปซึ่งจะกล่าวถึงในรายงานข้อบกพร่อง 637 กฎการเรียงลำดับและตัวอย่างไม่เห็นด้วย
3. กฎการเรียงลำดับใหม่ยังทำให้ ++++ i; กำหนดไว้อย่างดีใน C ++ 11
กฎการเรียงลำดับใหม่ที่ใช้หลังจาก C ++ 03 หมายความว่า:
int i = 0 ;
++++i ;
ไม่มีพฤติกรรมที่ไม่ได้กำหนดใน C ++ 11 อีกต่อไป
4. กะซ้ายซ้ายที่มีความหมายมากกว่าเล็กน้อย
ร่างต่อมาของภาษา C ++ 11 รวมN3485
ซึ่งผมลิงค์ข้างล่างนี้คงไม่ได้กำหนดพฤติกรรมของการขยับ 1 บิตเข้าหรือที่ผ่านมาบิตเครื่องหมาย นอกจากนี้ยังจะครอบคลุมในรายงานข้อบกพร่อง 1457 Howard Hinnant แสดงความคิดเห็นเกี่ยวกับความสำคัญของการเปลี่ยนแปลงนี้ในเธรดบนการเลื่อนซ้าย (<<) พฤติกรรมที่ไม่ได้กำหนดจำนวนเต็มลบใน C ++ 11 หรือไม่ .
5. ฟังก์ชัน constexpr สามารถใช้เป็นนิพจน์ค่าคงที่เวลาแบบคอมไพล์ใน C ++ 11
C ++ 11 แนะนำฟังก์ชันconstexprซึ่ง:
ตัวระบุ constexpr ประกาศว่าเป็นไปได้ที่จะประเมินค่าของฟังก์ชันหรือตัวแปร ณ เวลารวบรวม ตัวแปรและฟังก์ชั่นดังกล่าวนั้นสามารถใช้งานได้เฉพาะเมื่อได้รับอนุญาตให้มีการแสดงออกอย่างต่อเนื่องคงที่ของเวลา
ในขณะที่ C ++ 03 ไม่ได้มีconstexprคุณสมบัติที่เราไม่จำเป็นต้องใช้อย่างชัดเจนconstexprคำหลักตั้งแต่ห้องสมุดมาตรฐานให้หลายหน้าที่ใน C ++ 11 constexpr ยกตัวอย่างเช่นมาตรฐาน :: numeric_limits :: นาที ซึ่งสามารถนำไปสู่พฤติกรรมที่แตกต่างเช่น:
#include <limits>
int main()
{
int x[std::numeric_limits<unsigned int>::min()+2] ;
}
การใช้clang
ใน C ++ 03 สิ่งนี้จะทำให้x
เป็นอาร์เรย์ความยาวผันแปรซึ่งเป็นส่วนขยายและจะสร้างคำเตือนต่อไปนี้:
warning: variable length arrays are a C99 feature [-Wvla-extension]
int x[std::numeric_limits<unsigned int>::min()+2] ;
^
ในขณะที่ C ++ 11 std::numeric_limits<unsigned int>::min()+2
เป็นนิพจน์ค่าคงที่เวลาคอมไพล์และไม่ต้องการส่วนขยาย VLA
6. ใน C ++ 11 ข้อยกเว้นข้อยกเว้น noexcept ถูกสร้างขึ้นโดยปริยายสำหรับ destructors ของคุณ
เนื่องจากใน C ++ 11 destructor ที่ผู้ใช้กำหนดเองมีnoexcept(true)
ข้อกำหนดโดยนัยตามที่อธิบายไว้ในตัวทำลายล้าง noexceptนั่นหมายความว่าโปรแกรมต่อไปนี้:
#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";
}
ใน C ++ 11 จะโทรstd::terminate
แต่จะทำงานได้สำเร็จใน C ++ 03
7. ใน C ++ 03 เท็มเพลตอาร์กิวเมนต์ไม่สามารถมีการเชื่อมโยงภายใน
นี้ได้รับการคุ้มครองอย่างในทำไมมาตรฐาน :: เรียงลำดับไม่ยอมรับการเรียนการเปรียบเทียบประกาศภายในฟังก์ชั่น ดังนั้นรหัสต่อไปนี้ไม่ควรทำงานใน 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;
}
}
แต่ขณะนี้clang
ช่วยให้รหัสนี้ใน C ++ 03 โหมดที่มีคำเตือนถ้าคุณใช้-pedantic-errors
ธงซึ่งเป็นชนิดของเหนอะเห็นมันมีชีวิตอยู่
8. >> จะไม่ถูกสร้างขึ้นอีกต่อไปเมื่อปิดเทมเพลตหลาย ๆ
การใช้>>
เพื่อปิดเทมเพลตหลายรายการนั้นไม่ได้มีรูปแบบที่ไม่ดีอีกต่อไป แต่สามารถนำไปสู่โค้ดที่มีผลลัพธ์ต่างกันใน C ++ 03 และ C + 11 ตัวอย่างด้านล่างนำมาจากวงเล็บมุมฉากและความเข้ากันได้ย้อนหลัง :
#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';
}
และผลลัพธ์ใน C ++ 03 คือ:
0
3
และใน C ++ 11:
0
0
9. C ++ 11 เปลี่ยนแปลง std :: vector constructors บางส่วน
รหัสที่แก้ไขเล็กน้อยจากคำตอบนี้แสดงให้เห็นว่าการใช้ตัวสร้างต่อไปนี้จากstd :: vector :
std::vector<T> test(1);
สร้างผลลัพธ์ที่แตกต่างใน C ++ 03 และ 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. การ จำกัด การแปลงใน initializers รวม
ใน C ++ 11 การแปลงที่แคบลงใน initializers รวมนั้นเป็นรูปแบบที่ไม่ดีและดูเหมือนว่าgcc
จะอนุญาตให้ทำได้ทั้งใน C ++ 11 และ C ++ 03 แม้ว่าจะมีคำเตือนตามค่าเริ่มต้นใน C ++ 11:
int x[] = { 2.0 };
สิ่งนี้ครอบคลุมอยู่ในร่างมาตรฐาน C ++ 11 ส่วน8.5.4
การเริ่มต้นรายการย่อหน้า3 :
รายการเริ่มต้นของวัตถุหรือการอ้างอิงประเภท T ถูกกำหนดดังนี้
และมีสัญลักษณ์แสดงหัวข้อต่อไปนี้ ( เหมืองของการเน้น ):
มิฉะนั้นถ้า T เป็นประเภทคลาสจะพิจารณาตัวสร้าง ตัวสร้างที่ใช้งานได้จะถูกระบุและสิ่งที่ดีที่สุดจะถูกเลือกผ่านการแก้ปัญหาการโหลดเกิน (13.3, 13.3.1.7) หากจำเป็นต้องทำการแปลงให้แคบลง (ดูด้านล่าง) เพื่อแปลงข้อโต้แย้งใด ๆ โปรแกรมนั้นจะมีรูปแบบไม่ดี
นี้และอื่น ๆ อีกมากมายเช่นได้รับความคุ้มครองในร่าง c ++ มาตรฐานส่วนannex C.2
C ++ และ ISO c ++ 2003 รวมถึง:
ตัวอักษรสตริงชนิดใหม่ [... ] โดยเฉพาะแมโครชื่อ R, u8, u8R, u, uR, U, UR หรือ LR จะไม่ถูกขยายเมื่ออยู่ติดกับตัวอักษรสตริง แต่จะตีความเป็นส่วนหนึ่งของตัวอักษรสตริง . ตัวอย่างเช่น
#define u8 "abc"
const char *s = u8"def"; // Previously "abcdef", now "def"
การสนับสนุนสตริงตัวอักษรที่ผู้ใช้กำหนด [... ] ก่อนหน้านี้ # 1 จะประกอบด้วยโทเค็นการประมวลผลล่วงหน้าสองชุดแยกกันและแมโคร _x จะถูกขยาย ในมาตรฐานสากลฉบับนี้ # 1 ประกอบด้วยโทเค็นการประมวลผลล่วงหน้าเพียงครั้งเดียวดังนั้นจึงไม่ได้ขยายมาโคร
#define _x "there"
"hello"_x // #1
ระบุการปัดเศษสำหรับผลลัพธ์ของรหัสจำนวนเต็ม / และ% [... ] 2003 ที่ใช้การหารจำนวนเต็มปัดผลลัพธ์เป็น 0 หรือไปทางอนันต์ลบในขณะที่มาตรฐานสากลนี้ปัดผลลัพธ์เป็น 0 เสมอ
ความซับซ้อนของขนาดสมาชิก () ฟังก์ชั่นสมาชิกคงที่ [... ] การใช้งานคอนเทนเนอร์บางอย่างที่สอดคล้องกับ C ++ 2003 อาจไม่สอดคล้องกับข้อกำหนดขนาด () ที่ระบุในมาตรฐานสากลนี้ การปรับคอนเทนเนอร์เช่นรายการ std :: เป็นข้อกำหนดที่เข้มงวดอาจต้องการการเปลี่ยนแปลงที่เข้ากันไม่ได้
เปลี่ยนคลาสพื้นฐานของ std :: ios_base :: failure [... ] std :: ios_base :: failure ไม่ได้มาโดยตรงจาก std :: exception อีกต่อไป แต่ตอนนี้ได้มาจาก std :: system_error ซึ่งได้มาจาก มาตรฐาน :: runtime_error รหัส C ++ 2003 ที่ถูกต้องซึ่งถือว่า std :: ios_base :: failure ได้มาโดยตรงจาก std :: exception อาจทำงานแตกต่างกันในมาตรฐานสากลนี้
auto
จะส่งผลให้สถานการณ์เช่นนี้