2010-03-01 31 views
5

Tôi đã thử các mã sau:quá tải << nhà điều hành và đệ quy

#include <iostream> 
using std::cout; 
using std::ostream; 

class X 
{ 
public: 
    friend ostream& operator<<(ostream &os, const X& obj) 
    { 
     cout << "hehe";   // comment this and infinite loop is gone 
     return (os << obj); 
    } 
}; 

int main() 
{ 
    X x; 
    cout << x; 
    return 0; 
} 

Khi tôi biên dịch & chạy này, nó như mong đợi; một vòng lặp vô hạn. Nếu tôi xóa câu lệnh cout bên trong chức năng bạn bè, việc đệ quy sẽ không xảy ra. Tại sao nó như vậy?

+0

Đang sử dụng MinGW (GNU tối thiểu cho Windows) btw. – legends2k

+1

Làm thế nào để bạn nhận thấy sự đệ quy không xảy ra? Nó có kết thúc chương trình đúng không? Hay nó không in được gì và bạn phải chấm dứt nó? (Lưu ý rằng việc đệ quy đuôi có thể khiến bạn không nhận được tràn ngăn xếp). –

+0

@ litb: Vô tình rơi xuống nhà ga (tôi không nhấn một phím nào để giết quá trình này). – legends2k

Trả lời

7

Trình tối ưu hóa quyết định tất cả hoạt động còn lại của bạn không có hiệu lực và tối ưu hóa nó đi. Cho dù đúng hay sai là một vấn đề khác.

Đặc biệt:

X x; 

tạo rỗng đối tượng "x"

cout << x; 

cuộc gọi:

return (os << obj); 

được phụ thêm đối tượng rỗng; các thông báo trình biên dịch 'os' đã không phát triển bất kỳ kể từ cuộc gọi cuối cùng và cho thấy không có lời hứa làm như vậy nữa (và không có gì khác xảy ra) vì vậy nó quyết định toàn bộ doanh nghiệp là dư thừa và có thể được cắt ngắn vào thời điểm này.

Trong trường hợp bạn gọi

cout << "hehe";   // comment this and infinite loop is gone 

có một số hoạt động phụ nên các ưu không loại bỏ các cuộc gọi tiếp theo.

Tôi đoán nếu bạn đã khởi tạo x với bất kỳ thứ gì không trống hoặc đã thực hiện bất kỳ hoạt động nào khác không phải là, bạn sẽ có đệ quy chạy giống nhau.

+0

Thực ra tôi nghĩ rằng trình tối ưu hóa sẽ hoàn toàn đúng nếu tiêu chuẩn quy định rằng đệ quy vô hạn gây ra "hành vi không xác định"; không làm gì cả sẽ là OK trong trường hợp đó. Tôi không thể tìm thấy một bản sao của tiêu chuẩn C++ trên mạng, bất cứ ai có thể kiểm tra nó? –

+0

... trên lưu ý không liên quan, tôi tự hỏi nếu cuộc gọi được đính kèm trong 'try-catch (...)' để nắm bắt ngoại lệ tràn ngăn xếp.Mà, tôi nghĩ, sẽ là khá nhiều hành vi mong đợi, sửa tôi nếu tôi sai. –

+1

Tôi không nghĩ rằng ngoại lệ như vậy (rằng, bằng cách này, không phải là một ngoại lệ C + +, nhưng nó là một số loại tín hiệu trên * NIX và một ngoại lệ SEH trên Windows) có thể bị bắt. Trên thực tế, không có gì bạn có thể làm khi ngăn xếp tràn: mọi thứ đã biến mất. Nếu bạn nhận thấy, các ứng dụng Windows bị tràn ngăn xếp thậm chí không hiển thị thông báo lỗi, bởi vì chúng không thể làm bất kỳ điều gì bây giờ mà không còn ngăn xếp nữa. –

6

Trong cả hai trường hợp (có và không có văn bản "hehe") Visual Studio 2005 cung cấp cho các cảnh báo sau đây:

warning C4717: 'operator<<' : recursive on all control paths, function will cause runtime stack overflow 

Trong cả hai trường hợp nó biên dịch và trong cả hai trường hợp nó mang lại một chồng tràn.

Tuy nhiên, không có "hehe", luồng tràn ngăn xếp xảy ra sớm hơn một chút.

+0

Bạn nói đúng Patrick, cảm ơn! Và nhờ vào litb để nghi ngờ tính hợp lệ của sự lúng túng của tôi mà đệ quy không xảy ra, điều đó khiến tôi chạy nó thông qua 'gdb' và bây giờ tôi hài lòng khi thấy' SIGSEGV' chứng minh rằng trong cả hai trường hợp đệ quy xảy ra :) – legends2k

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