2010-03-09 7 views
12

Tôi tự hỏi, không có mục đích nào khác ngoài sự tò mò thuần khiết (vì không ai nên viết mã như thế này!) Về cách hành vi của RAII mắt lưới với việc sử dụng goto (ý tưởng đáng yêu phải không) .Điều gì xảy ra khi chúng tôi kết hợp RAII và GOTO?

class Two 
{ 
public: 
    ~Two() 
    { 
     printf("2,"); 
    } 
}; 

class Ghost 
{ 
public: 
    ~Ghost() 
    { 
     printf(" BOO! "); 
    } 
}; 

void foo() 
{ 
    { 
     Two t; 
     printf("1,"); 
     goto JUMP; 
    } 
    Ghost g; 
JUMP: 
    printf("3"); 
} 

int main() 
{ 
     foo(); 
} 

Khi chạy mã sau trong Visual Studio 2005, tôi nhận được kết quả sau.

1,2,3 BOO! 

Tuy nhiên tôi tưởng tượng, đoán, hy vọng rằng 'BOO!' sẽ không thực sự xuất hiện như là Ghost nên chưa bao giờ được khởi tạo (IMHO, vì tôi không biết hành vi mong đợi thực tế của mã này).

Có chuyện gì?


Tôi chỉ nhận ra rằng nếu tôi nhanh chóng một nhà xây dựng rõ ràng cho Ghost mã không biên dịch ...

class Ghost 
{ 
public: 
    Ghost() 
    { 
     printf(" HAHAHA! "); 
    } 
    ~Ghost() 
    { 
     printf(" BOO! "); 
    } 
}; 

Ah, những bí ẩn ...

+1

Tôi tin rằng hành vi là chính xác. Nếu không, làm thế nào bạn có thể tham khảo biến g sau khi JUMP? – leiz

+2

http://xkcd.com/292/ –

Trả lời

23

Các cuộc đàm phán về tiêu chuẩn điều này một cách rõ ràng - với một ví dụ; 6.7/3 "Tuyên bố khai báo" (nhấn mạnh do tôi thêm):

Các biến có thời gian lưu trữ tự động được khởi chạy mỗi khi khai báo câu lệnh được thực thi. Các biến có thời gian lưu trữ tự động được khai báo trong khối sẽ bị hủy khi thoát khỏi khối.

Có thể chuyển thành một khối, nhưng không phải theo cách bỏ qua các khai báo có khởi tạo. Một chương trình nhảy từ một điểm mà một biến cục bộ với thời gian lưu trữ tự động không nằm trong phạm vi đến một điểm mà nó nằm trong phạm vi không đúng định dạng trừ khi biến có kiểu POD và được khai báo không có bộ khởi tạo.

[Ví dụ:

void f() 
{ 
    //... 
    goto lx; //ill-formed: jump into scope of a 
    //... 

ly: 
    X a = 1; 
    //... 

lx: 
    goto ly; //OK, jump implies destructor 
       //call for a, followed by construction 
       //again immediately following label ly 
} 

-end dụ]

Vì vậy, có vẻ như với tôi rằng hành vi MSVC là không tiêu chuẩn phù hợp - Ghost không phải là một loại POD, vì vậy trình biên dịch nên ban hành một lỗi khi câu lệnh goto được mã hóa để nhảy qua nó.

Một vài trình biên dịch khác mà tôi đã thử (GCC và Digital Mars) phát hành lỗi. Comeau đưa ra một cảnh báo (nhưng trong sự công bằng, kịch bản xây dựng của tôi cho Comeau có cấu hình cho khả năng tương thích MSVC cao, vì vậy nó có thể theo sau ý định của Microsoft).

+1

Cảm ơn bạn đã tìm kiếm vị trí được xác định trong tiêu chuẩn! Tuy nhiên, tôi tự hỏi nếu hình thành không chính xác có nghĩa là nó nên hoặc không nên biên dịch ... –

+0

"Ill-hình thành" có nghĩa là chương trình không phải là "hình thành tốt." Trình biên dịch được yêu cầu chỉ chấp nhận và "thực thi đúng" các chương trình được định dạng tốt. Đó là, nếu nó là "hình thành không đúng", đó là do lỗi. – greyfade

+0

@Robert: Tôi đã thêm một vài từ về hành vi của MSVC tại đây, như tôi đã thực hiện ban đầu. –

0

Goto không phải là phóng xạ. Rời khỏi goto có chút khác biệt so với việc rời khỏi ngoại lệ. Nhập bởi goto nên được quyết định bởi sự tiện lợi, không phải là giới hạn của ngôn ngữ. Không biết liệu ma có được xây dựng hay không là một lý do chính đáng để không làm điều đó.

Nhảy vào trước hàm tạo. Nếu bạn muốn nhảy vào sau khi một số đối tượng đã được xây dựng, kèm theo nó trong một phạm vi mới hoặc giải quyết cuộc sống của chính mình.

0

Trong trường hợp này, tôi đã tìm thấy cách tiếp cận sau hữu ích.

void foo() 
{ 
    { 
     Two t; 
     printf("1,"); 
     goto JUMP; 
    } 

    { 
     Ghost g; 
     // operations that use g. 
    } 

// g is out of scope, so following JUMP is allowed. 
JUMP: 
    printf("3"); 
} 

Việc xác định phạm vi biến g trong hàm foo() của bạn sẽ làm cho bước nhảy hợp pháp. Bây giờ, chúng tôi không nhảy từ một nơi mà g không được khởi tạo đến một nơi mà g được dự kiến ​​sẽ được khởi tạo.