2008-12-29 43 views

Trả lời

29

hủy bỏ gửi tín hiệu SIGABRT, thoát chỉ đóng ứng dụng thực hiện dọn dẹp bình thường.

Bạn có thể xử lý tín hiệu hủy bỏ theo bất kỳ cách nào bạn muốn, nhưng hành vi mặc định là đóng ứng dụng cũng như với mã lỗi.

hủy bỏ sẽ không thực hiện hủy đối tượng thành viên tĩnh và toàn cầu của bạn, nhưng thoát khỏi sẽ.

Tất nhiên khi ứng dụng được đóng hoàn toàn, hệ điều hành sẽ giải phóng mọi bộ nhớ không xác định và các tài nguyên khác.

Trong cả hai hủy bỏthoát chương trình chấm dứt (giả sử bạn không ghi đè lên hành vi mặc định), mã trả về sẽ được trả lại cho quá trình cha mẹ mà bắt đầu ứng dụng của bạn.

Xem ví dụ sau:

SomeClassType someobject; 

void myProgramIsTerminating1(void) 
{ 
    cout<<"exit function 1"<<endl; 
} 

void myProgramIsTerminating2(void) 
{ 
    cout<<"exit function 2"<<endl; 
} 

int main(int argc, char**argv) 
{ 
    atexit (myProgramIsTerminating1); 
    atexit (myProgramIsTerminating2); 
    //abort(); 
    return 0; 
} 

Bình luận:

  • Nếu hủy bỏ là không chú thích: không có gì được in và destructor của SomeObject sẽ không được gọi.

  • Nếu hủy bỏ được nhận xét như trên: destructor SomeObject sẽ được gọi là bạn sẽ nhận được kết quả như sau:

chức năng exit 2
chức năng exit 1

+0

Ở đây, nó được gọi là chức năng thoát 2 chức năng thoát THEN 1. gcc 4, Linux 2.6. – strager

+1

Trang người dùng cho atexit nói: "Chức năng [đã đăng ký sử dụng atexit] được gọi theo thứ tự ngược lại; không có đối số nào được chuyển." – strager

+0

@strager là đúng, các chức năng được đăng ký bởi atexit được cho là được gọi theo thứ tự ngược lại khi thoát ra được gọi là hoặc trả về chính. –

106

abort() thoát khỏi chương trình của bạn mà không cần gọi các chức năng đã đăng ký sử dụng atexit() trước tiên và không cần gọi các đối tượng cấu trúc đầu tiên. exit() thực hiện cả hai trước khi thoát khỏi chương trình của bạn. Nó không gọi destructors cho các đối tượng tự động mặc dù. Vì vậy,

A a; 
void test() { 
    static A b; 
    A c; 
    exit(0); 
} 

sẽ hủy ab đúng, nhưng sẽ không gọi destructor của c. abort() sẽ không gọi destructors của cả hai đối tượng. Vì đây là không may, cáC++ Chuẩn C mô tả một cơ chế thay thế đảm bảo đúng chấm dứt:

Đối tượng với thời gian lưu trữ tự động đều bị phá hủy trong một chương trình có chức năng main() không chứa đối tượng tự động và thực hiện các cuộc gọi đến exit(). Kiểm soát có thể được chuyển trực tiếp đến một số main() như vậy bằng cách ném một ngoại lệ bị bắt trong main().

struct exit_exception { 
    int c; 
    exit_exception(int c):c(c) { } 
}; 

int main() { 
    try { 
     // put all code in here 
    } catch(exit_exception& e) { 
     exit(e.c); 
    } 
} 

Thay vì gọi exit(), sắp xếp mã throw exit_exception(exit_code); để thay thế.

+1

+1 bởi vì, trong khi Brian R.Bondy là tốt, bạn đã làm tăng vấn đề hủy bỏ/thoát (không phải là destructor của các đối tượng stack được gọi), và cung cấp sự thay thế cho một quá trình C++ RAII chuyên sâu. – paercebal

+0

Tôi đã tìm kiếm một cách để thoát khỏi một chương trình mà không cần gọi dtor và câu trả lời của bạn chỉ là những gì tôi đang tìm kiếm! Cảm ơn – acemtp

+0

Đó là điều hoàn toàn chính xác, nếu nó thực sự quan trọng rằng các đối tượng tự động của bạn không được gọi là :-) –

4

abort gửi tín hiệu SIGABRT. abort không trở lại người gọi. Trình xử lý mặc định cho tín hiệu SIGABRT đóng ứng dụng. stdio luồng tệp bị xóa, sau đó đóng. Tuy nhiên, các trình phá hủy cho các cá thể lớp C++ không phải là (không chắc chắn về trường hợp này - có lẽ kết quả là không xác định?).

exit có các cuộc gọi lại riêng, được đặt bằng atexit. Nếu callbacks được chỉ định (hoặc chỉ một), chúng được gọi theo thứ tự ngược lại thứ tự đăng ký của chúng (giống như một ngăn xếp), sau đó thoát khỏi chương trình. Như với abort, exit không trả lại người gọi. stdio luồng tệp bị xóa, sau đó đóng. Ngoài ra, các destructors cho các cá thể lớp C++ được gọi.

+0

thoát có thể có nhiều chức năng gọi lại được đăng ký thông qua atexit, khi thoát được gọi là tất cả các chức năng gọi lại sẽ được gọi theo thứ tự ngược lại mà chúng đã được đăng ký. –

+0

@Gamble, Tất nhiên, tôi đã đề cập đến bản thân mình một vài phút trước trong một bình luận cho câu trả lời của @ Bondy. Tôi sẽ chỉnh sửa câu trả lời của riêng mình để phản ánh điều đó. – strager

5

Từ exit() trang hướng dẫn:

Các exit() chức năng gây ra bình thường chấm dứt quá trình và giá trị của tình trạng & 0377 được trả lại cho phụ huynh.

Từ việc hủy bỏ() trang hướng dẫn:

Các abort() đầu tiên unblocks tín hiệu SIGABRT, và sau đó đặt ra rằng tín hiệu cho quá trình gọi. Điều này dẫn đến kết thúc bất thường của quá trình trừ khi tín hiệu SIGABRT bị bắt và tín hiệu xử lý không trả lại.

10

Những điều sau đây xảy ra khi một chương trình gọi exit():

  • Chức năng đăng ký bởi atexit chức năng được thực hiện
  • Tất cả suối mở là đỏ ửng và đóng cửa, các file được tạo ra bởi tmpfile được loại bỏ
  • Chương trình chấm dứt bằng mã thoát được chỉ định cho máy chủ

Chức năng abort() gửi tín hiệu SIGABRT đến quy trình hiện tại, nếu không bị bắt chương trình bị chấm dứt mà không đảm bảo rằng các luồng đang mở bị xóa/đóng hoặc các tệp tạm thời được tạo qua tmpfile bị xóa, atexit chức năng đã đăng ký không được gọi và trạng thái thoát khác không được trả về máy chủ.

+0

hmm. tiêu chuẩn cho biết chương trình chỉ không bị chấm dứt nếu trình xử lý tín hiệu "không trả lại". bạn khá tốt với C. bạn có thể tưởng tượng bất kỳ kịch bản nào có thể khiến nó tiếp tục thực hiện bình thường mà không quay trở lại? tôi tưởng tượng longjmp, nhưng tôi không chắc chắn về cách nó hoạt động trong xử lý tín hiệu. –

+0

Nói chung, việc gọi longjmp từ bộ xử lý tín hiệu là không xác định nhưng có trường hợp đặc biệt khi tín hiệu được tạo ra bằng cách tăng/hủy vì vậy tôi đoán điều này về lý thuyết có thể mặc dù tôi không nghĩ mình đã từng thấy nó. Bây giờ tôi sẽ phải thử nó;) –

+1

Điều này dường như làm việc (chia thành nhiều bài viết do 300 char hạn): #include #include #include #include dễ bay hơi sig_atomic_t do_abort = 1; jmp_buf env; void abort_handler (int i) {do_abort = 0; longjmp (env, 1);} –

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