2012-02-06 34 views
12

tôi đã làm mới sự hiểu biết của tôi về giá trị khởi động so với mặc định-khởi động, và tình cờ gặp this:Tại sao hành vi này không được xác định đơn giản?

struct C { 
    int x; 
    int y; 
    C() { } 
}; 

int main() { 
    C c = C(); 
} 

Rõ ràng đây là UB vì

Trong trường hợp C(), có một constructor có khả năng khởi tạo các thành viên x và y, vì vậy không có khởi tạo diễn ra. Cố gắng sao chép C() thành c do đó dẫn đến hành vi không xác định.

Tôi nghĩ rằng tôi hiểu tại sao, nhưng tôi không chắc chắn. Ai đó có thể vui lòng xây dựng?

Điều đó có nghĩa là đây cũng là UB?

int x; x = x; 

Ngẫu nhiên, liên quan đến khởi tạo giá trị, sau đây có được đảm bảo bằng không không?

int x = int(); 
+0

Không chắc chắn ý của bạn là gì. Nếu bạn có nghĩa là giá trị của x và y sẽ được uninitialized sau đó có, nhưng bạn đã trả lời câu hỏi của riêng bạn sau đó (như constructor không làm việc đó). Đối với C c = C(); Tôi nghĩ điều đó hoàn toàn hợp lệ. – Sid

+0

Tôi nghĩ nó cũng hoàn toàn hợp lệ, cho đến khi ai đó tuyên bố khác. Khi tôi đọc nó, đoạn đầu tiên chỉ có thể bằng UB nếu đoạn thứ hai cũng là, nếu không nó là một giá trị uninitialised đơn giản, không có mũi deamons. – spraff

+2

@Sid: Không, sử dụng giá trị của đối tượng chưa được khởi tạo cho hành vi không xác định. –

Trả lời

13

ví dụ đầu tiên của bạn đã không xác định hành vi bởi vì mặc định, trình biên dịch tạo constructor sao chép sẽ làm một bản sao memberwise, int s có thể có giá trị bẫy, và đọc một giá trị bẫy để sao chép nó có thể gây ra các chương trình sụp đổ.

Trong thực tế, tôi không thể tưởng tượng điều này bao giờ thực sự bị rơi; trình biên dịch gần như chắc chắn sẽ tối ưu hóa bản sao ra, và thậm chí nếu không, nó có khả năng sẽ sử dụng một số bản sao bitwise đặc biệt mà sẽ sao chép mà không cần kiểm tra giá trị bẫy của . (Trong C++, bạn được đảm bảo có thể byte sao chép.)

Đối với trường hợp thứ hai, một lần nữa, hành vi không xác định. Mặc dù trong trường hợp này, bạn có bài tập thay vì sao chép bản dựng và trình biên dịch là ít có khả năng tối ưu hóa nó hơn. (Không có bài tập nào trong ví dụ đầu tiên của bạn, chỉ sao chép bản dựng.)

Đối với thứ ba, có. Trình khởi tạo có parenthese trống (và không có trình khởi tạo mặc định do người dùng xác định ghi đè nó) trước tiên thực hiện số không khởi tạo (chính xác như xảy ra cho các biến có tuổi thọ tĩnh).

+0

+1, một số công cụ gỡ lỗi chạy ứng dụng trong máy ảo có bẫy (trong một số trường hợp) xác định đây là vấn đề tiềm ẩn. Nhưng tôi đồng ý rằng trong một kịch bản trường hợp thực tế có thể là bạn sẽ chỉ cần sao chép bộ nhớ uninitialized và di chuyển nó xung quanh. –

+0

Trong C++ 14 tham chiếu là [dcl.init]/12 "] Nếu một giá trị không xác định được tạo ra bởi một đánh giá, hành vi không được xác định ngoại trừ trong các trường hợp sau:" - và không có trường hợp nào bao gồm mã này –

-1

No. Điều gì sẽ xảy ra là hầu hết các trình biên dịch sẽ không thay đổi giá trị của x. Nó giống với mã sau:

int x = 0; 
x = 0; 

Nó không phải là dòng thứ hai sẽ không thực thi, nó sẽ không làm gì cả.

+0

Vấn đề là nếu đoạn trích được đăng của tôi là UB thì tối ưu hóa trình biên dịch có thể gây ra kết quả * bất kỳ *. – spraff

+3

Tôi không đồng ý, về mặt kỹ thuật đọc từ một giá trị không được đặt là hành vi không xác định. Cho dù trình biên dịch tối ưu hóa đọc đi là * một * của kết quả có thể có của hành vi không xác định. –

1

Tôi không nghĩ rằng đây thực sự là undefined behavior mặc dù các giá trị trong cunspecified values. Nghĩa là, hành vi của chương trình cũng được xác định miễn là bạn không kết thúc bằng cách sử dụng các giá trị không xác định này. Nếu bạn sử dụng chúng, ví dụ: trong điều kiện hoặc in chúng, kết quả không được xác định. Tuy nhiên, tôi không nghĩ rằng chương trình được phép làm bất cứ điều gì kỳ lạ.

Đối với việc sử dụng hàm tạo mặc định trên các kiểu dựng sẵn, điều này đảm bảo mang lại giá trị bằng không, ví dụ: 0 cho số nguyên, 0.0 cho loại điểm động, v.v. constructor. Khi có bất kỳ hàm tạo nào, bạn cần phải quan tâm đến việc xây dựng các thành viên của bạn mà không cần một hàm tạo.

+1

Ooh, bạn so với James Kanze trong một cuộc đấu súng thẳng! Ông nói rằng các nhà xây dựng bản sao "sử dụng" các giá trị uninitialized, và làm như vậy là UB. Bạn nói khác đi. –

+0

@SteveJessop nhưng câu trả lời này có vẻ chính xác hơn, phải không? :), +1 –

+0

@ Mr.Anubis: dường như có sự bất đồng ở mức cao nhất những gì bạn có thể làm trong C++ với giá trị chưa được khởi tạo. Có một số văn bản trong tiêu chuẩn nói rằng bạn không thể thực hiện một chuyển đổi rvalue-rvalue, nhưng người ta sẽ nghĩ rằng (chung với các đại diện đối tượng khác), bạn có thể truy cập nó như là 'unsigned char'. Trong thực tế, nó không chắc rằng ctor sao chép được tạo ra làm bất cứ điều gì khác hơn là sao chép dữ liệu một cách mù quáng, nhưng để chơi an toàn tôi tin rằng James là chính xác về những gì tiêu chuẩn cho phép. ví dụ: sao chép có thể ngẫu nhiên kiểm tra các bit chẵn lẻ, nếu 'int' có bất kỳ, với UB nếu chúng sai. –

Các vấn đề liên quan