Có, có một số thay đổi sẽ khiến cùng một mã dẫn đến hành vi khác nhau giữa C ++ 03 và C ++ 11. Sự khác biệt về quy tắc giải trình tự tạo ra một số thay đổi thú vị bao gồm một số hành vi chưa được xác định trước đó trở nên được xác định rõ.
1. nhiều đột biến của cùng một biến trong danh sách khởi tạo
Một trường hợp góc rất thú vị sẽ có nhiều đột biến của cùng một biến trong danh sách khởi tạo, ví dụ:
int main()
{
int count = 0 ;
int arrInt[2] = { count++, count++ } ;
return 0 ;
}
Trong cả C ++ 03 và C ++ 11, điều này được xác định rõ nhưng thứ tự đánh giá trong C ++ 03 là không xác định nhưng trong C ++ 11, chúng được đánh giá theo thứ tự xuất hiện . Vì vậy, nếu chúng tôi biên dịch bằng clang
chế độ C ++ 03, nó sẽ đưa ra cảnh báo sau ( xem trực tiếp ):
warning: multiple unsequenced modifications to 'count' [-Wunsequenced]
int arrInt[2] = { count++, count++ } ;
^ ~~
nhưng không cung cấp cảnh báo trong C ++ 11 ( xem trực tiếp ).
2. Quy tắc sắp xếp mới làm cho i = ++ i + 1; được xác định rõ trong C ++ 11
Các quy tắc giải trình tự mới được thông qua sau C ++ 03 có nghĩa là:
int i = 0 ;
i = ++ i + 1;
không còn là hành vi không xác định trong C ++ 11, điều này được đề cập trong báo cáo lỗi 637. Quy tắc tuần tự và ví dụ không đồng ý
3. Quy tắc sắp xếp mới cũng làm cho ++++ i; được xác định rõ trong C ++ 11
Các quy tắc giải trình tự mới được thông qua sau C ++ 03 có nghĩa là:
int i = 0 ;
++++i ;
không còn là hành vi không xác định trong C ++ 11.
4. Các ca trái được ký hợp lý hơn một chút
Các bản nháp sau này của C ++ 11 bao gồm N3485
những gì tôi liên kết bên dưới đã cố định hành vi không xác định của việc chuyển 1 bit vào hoặc qua bit dấu . Điều này cũng được đề cập trong báo cáo lỗi 1457 . Howard Hinnant đã nhận xét về tầm quan trọng của sự thay đổi này trong luồng trên Dịch chuyển trái (<<) có phải là số nguyên âm không xác định hành vi trong C ++ 11 không? .
5. Hàm constexpr có thể được coi là biểu thức hằng số thời gian biên dịch trong C ++ 11
C ++ 11 đã giới thiệu các hàm constexpr trong đó:
Trình xác định constexpr tuyên bố rằng có thể đánh giá giá trị của hàm hoặc biến tại thời gian biên dịch. Các biến và hàm như vậy sau đó có thể được sử dụng khi chỉ cho phép biên dịch các biểu thức hằng số thời gian.
trong khi C ++ 03 không có tính năng constexpr, chúng tôi không phải sử dụng rõ ràng từ khóa constexpr vì thư viện chuẩn cung cấp nhiều chức năng trong C ++ 11 dưới dạng constexpr . Ví dụ: std :: num_limits :: min . Điều này có thể dẫn đến hành vi khác nhau, ví dụ:
#include <limits>
int main()
{
int x[std::numeric_limits<unsigned int>::min()+2] ;
}
Sử dụng clang
trong C ++ 03, điều này sẽ gây ra x
một mảng có chiều dài thay đổi, là một phần mở rộng và sẽ tạo ra cảnh báo sau:
warning: variable length arrays are a C99 feature [-Wvla-extension]
int x[std::numeric_limits<unsigned int>::min()+2] ;
^
trong khi trong C ++ 11 std::numeric_limits<unsigned int>::min()+2
là biểu thức hằng số thời gian biên dịch và không yêu cầu mở rộng VLA.
6. Trong C ++, các đặc tả ngoại lệ không ngoại lệ được tạo hoàn toàn cho các hàm hủy của bạn
Vì trong C ++ 11 hàm hủy được xác định bởi người dùng có noexcept(true)
đặc tả ngầm định như được giải thích trong các hàm hủy không có ngoại lệ, điều đó có nghĩa là chương trình sau:
#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";
}
Trong C ++ 11 sẽ gọi std::terminate
nhưng sẽ chạy thành công trong C ++ 03.
7. Trong C ++ 03, các đối số mẫu không thể có liên kết nội bộ
Điều này được trình bày độc đáo tại sao std :: sort không chấp nhận So sánh các lớp được khai báo trong một hàm . Vì vậy, đoạn mã sau không nên hoạt động trong 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;
}
}
nhưng hiện tại clang
cho phép mã này ở chế độ C ++ 03 với một cảnh báo trừ khi bạn sử dụng -pedantic-errors
cờ, loại icky, xem nó trực tiếp .
8. >> không còn hình thành khi đóng nhiều mẫu
Việc sử dụng >>
để đóng nhiều mẫu không còn được định hình nữa mà có thể dẫn đến mã với các kết quả khác nhau trong C ++ 03 và C + 11. Ví dụ dưới đây được lấy từ dấu ngoặc vuông và khả năng tương thích ngược :
#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';
}
và kết quả trong C ++ 03 là:
0
3
và trong C ++ 11:
0
0
9. C ++ 11 thay đổi một số hàm tạo std :: vector
Mã được sửa đổi một chút từ câu trả lời này cho thấy rằng sử dụng hàm tạo sau từ std :: vector :
std::vector<T> test(1);
tạo ra các kết quả khác nhau trong C ++ 03 và 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. Thu hẹp chuyển đổi trong tổng hợp khởi tạo
Trong C ++ 11, một chuyển đổi thu hẹp trong các trình khởi tạo tổng hợp không được định dạng và có vẻ như gcc
cho phép điều này trong cả C ++ 11 và C ++ 03 mặc dù nó cung cấp một cảnh báo theo mặc định trong C ++ 11:
int x[] = { 2.0 };
Này được đề cập trong dự thảo C ++ 11 phần chuẩn 8.5.4
List-khởi đoạn 3 :
Danh sách khởi tạo một đối tượng hoặc tham chiếu loại T được định nghĩa như sau:
và chứa viên đạn sau ( nhấn mạnh của tôi ):
Mặt khác, nếu T là một loại lớp, các hàm tạo được xem xét. Các hàm tạo có thể áp dụng được liệt kê và hàm tốt nhất được chọn thông qua độ phân giải quá tải (13.3, 13.3.1.7). Nếu một chuyển đổi thu hẹp (xem bên dưới) là bắt buộc để chuyển đổi bất kỳ đối số nào, thì chương trình không được định dạng
Này và nhiều ví dụ hơn được bao gồm trong dự thảo chuẩn C ++ phần annex C.2
C ++ và ISO C ++ 2003 . Nó cũng bao gồm:
Các loại chuỗi ký tự mới [...] Cụ thể, các macro có tên R, u8, u8R, u, uR, U, UR hoặc LR sẽ không được mở rộng khi liền kề với một chuỗi ký tự mà sẽ được hiểu là một phần của chuỗi ký tự . Ví dụ
#define u8 "abc"
const char *s = u8"def"; // Previously "abcdef", now "def"
Hỗ trợ chuỗi bằng chữ do người dùng định nghĩa [...] Trước đây, # 1 sẽ bao gồm hai mã thông báo tiền xử lý riêng biệt và macro _x sẽ được mở rộng. Trong Tiêu chuẩn quốc tế này, # 1 bao gồm một mã thông báo tiền xử lý duy nhất, vì vậy macro không được mở rộng.
#define _x "there"
"hello"_x // #1
Chỉ định làm tròn cho kết quả của số nguyên / và% [...] 2003 sử dụng phép chia số nguyên làm tròn kết quả về 0 hoặc hướng tới vô cực âm, trong khi Tiêu chuẩn quốc tế này luôn làm tròn kết quả về 0.
Độ phức tạp của các hàm thành viên kích thước () không đổi [...] Một số cách triển khai vùng chứa phù hợp với C ++ 2003 có thể không phù hợp với các yêu cầu kích thước () đã chỉ định trong Tiêu chuẩn quốc tế này. Điều chỉnh các thùng chứa như std :: list theo các yêu cầu khắt khe hơn có thể yêu cầu thay đổi không tương thích.
Thay đổi lớp cơ sở của std :: ios_base :: fail [...] std :: ios_base :: fail không còn xuất phát trực tiếp từ std :: ngoại lệ, nhưng bây giờ được lấy từ std :: system_error, từ đó có nguồn gốc từ std :: runtime_error. Mã C ++ 2003 hợp lệ giả định rằng std :: ios_base :: fail được lấy trực tiếp từ std :: ngoại lệ có thể thực thi khác trong Tiêu chuẩn quốc tế này.
auto
có thể dẫn đến một tình huống như thế này