2012-02-22 9 views
9

बाहर निकलने पर एक समारोह चला सकता हूँ मैं एक समारोह है कि मैं चलाने के लिए जब भी अपने कार्यक्रम बाहर निकलता चाहते हैं:कैसे आप C++

void foo() { 
    std::cout<< "Exiting" << std::endl; 
} 

मैं कैसे पंजीकृत करूं जब भी कार्यक्रम में मौजूद है यह चलाने के लिए, जब की परवाह किए बिना और यह क्यों निकलता है - सिग्नल के कारण, बाहर निकलें() कॉल, इत्यादि?

+0

सभी मामलों में संभव नहीं है - कुछ सिग्नल तुरंत प्रक्रिया को नीचे लाते हैं चाहे आप उन्हें चाहते हैं या नहीं। (उदाहरण के लिए ढेर ओवरफ्लो) –

+0

क्या ऑपरेटिंग सिस्टम? –

उत्तर

26

आप cstdlib शीर्षक में जिसे उपयुक्त नाम दिया std::atexit फ़ंक्शन का उपयोग कर सकते हैं:

#include <cstdlib> 

void exiting() { 
    std::cout << "Exiting"; 
} 

int main() { 
    std::atexit(exiting); 
} 

प्रणाली atexit के साथ पंजीकृत कार्यों के ढेर को बनाए रखने और उन्हें एक उनके पंजीकरण के विपरीत क्रम में कॉल करेंगे जब या तो exit समारोह कहा जाता है, या कार्यक्रम main से आता है। आप कम से कम 32 कार्यों को इस तरह से पंजीकृत कर सकते हैं।

+0

जिसे सिग्नल के बाद बुलाया नहीं जाता है या 'abort'/'terminate' के लिए कॉल नहीं किया जाता है। (कहते हैं: ** सामान्य प्रक्रिया समाप्ति पर कॉल करने के लिए एक फ़ंक्शन पंजीकृत करें **) –

+1

@ बिलीओनेल, यही कारण है कि मैंने कहा, "जब 'निकास' समारोह कहा जाता है या कार्यक्रम 'मुख्य' से आता है –

+0

श्वास, मेरी गलती :) –

3

आप इसे वैश्विक उदाहरण के साथ कक्षा के विनाशक में डाल सकते हैं।

class SomeGlobalStuff { 
    ~SomeGlobalStuff() { 
      foo(); 
    } 
    static SomeGlobalStuff instance; 
}; 
// putting this in a single compilation unit. 
SomeGlobalStuff SomeGlobalStuff::instance instance; 

लेकिन किसी अन्य विधि की तरह, आपको याद रखना होगा कि यदि आप गारंटी नहीं दे सकते कि यह अभी भी मौजूद है तो आप किसी भी डेटा का उपयोग नहीं कर सकते हैं। वैश्विक वस्तुओं का विघटन मनमाने ढंग से क्रम में किया जाता है, इसलिए मूल रूप से, आप foo() फ़ंक्शन में std :: cout का उपयोग नहीं कर सकते हैं। atexit() इस संबंध में बदतर है, क्योंकि वैश्विक वस्तुओं के विनाश से पहले या बाद में यह निष्पादित करता है कि संकलक और कंपाइलर विकल्पों पर निर्भर करता है।

और वैसे भी, आपको अभी भी संकेतों को सही तरीके से संभालना होगा। आपको चुनना होगा कि कौन से सिग्नल हैंडल हैं और कौन सा संभाल नहीं है (आप शायद एसआईजीएसईजीवी को संभालना नहीं चाहते हैं)। आप सिग्नल हैंडलिंग से बच नहीं सकते हैं। और याद रखें कि संकेत किसी भी समय आपके प्रोग्राम को बाधित कर सकते हैं (जब तक कि मुखौटा न हो) ताकि अपडेट के बीच में आपकी डेटा संरचनाएं मनमाने ढंग से स्थिति में हों।

+0

मेरा मानना ​​है कि मानक में भाषा है जो कहती है कि 'cout' हर जगह वैध है (पहले बनाया जाने वाला परिभाषित) लेकिन मुझे अभी यह नहीं मिल रहा है। यह संकेतों के लिए भी काम नहीं करता है, 'abort', 'terminate', आदि –

+0

@ बिलीओनेल:' abort' एक सिग्नल उठाता है (जिसे आपको संभालने के लिए चुनना चाहिए या नहीं, जैसा कि मैंने कहा था), 'टर्मिनेट' पूरी तरह से है अलग मामला इसके अलावा, शायद 'std :: cout' हमेशा मौजूद है, लेकिन 'abort()'' क्रियाओं को 'SIGABRT' बढ़ाने के लिए परिभाषित किया गया है और इसमें सभी खुली धाराओं पर 'fclose()' को प्रभावित करने का प्रयास शामिल हो सकता है। fclose (stdout) std :: cout को काम करने से रोक देगा। – BatchyX

+0

केवल उन प्रणालियों पर जिनके पास 'SIGABRT' जैसी चीज है। आपके सीआरटी के आधार पर 'fclose (stdout) 'std :: cout' काम करना बंद कर सकता है या नहीं हो सकता है। मानक मानक कंसोल इनपुट/आउटपुट/त्रुटि धाराओं और उनके सी समकक्ष फ़ाइल हैंडल के बीच संबंध (यदि कोई है) को परिभाषित नहीं करता है। जब मैं कहता हूं कि 'cout' हमेशा मान्य है, मेरा मतलब है कि यह अलग-अलग अनुवाद इकाइयों में परिभाषित गैर-स्थानीय स्थैतिक वस्तुओं के प्रारंभिकरण के आदेश को' अपरिभाषित 'नियम से प्रभावित नहीं है। शायद मैंने आपके जवाब को गलत समझा। –

1

प्रक्रिया के बाद नियंत्रण प्राप्त करने के लिए एकमात्र तरीका (यूनिक्स और यूनिक्स-जैसे ऑपरेटिंग सिस्टम में) wait(2) इसके लिए है। एक powerfail, कर्नेल आतंक, या मजबूर रिबूट की कमी, इस काम करना चाहिए:

#include <sys/types.h> 
#include <sys/wait.h> 
#include <iostream> 

int AtExit() { 
    pid_t pid = fork(); 
    if(pid < 0) return pid; 
    if(pid == 0) return pid; 
    pid = waitpid(pid, 0, 0); 
    return pid; 
} 

int main() { 
    if(AtExit()) { 
    std::cout << "Exiting\n"; 
    return 0; 
    } 

    std::cout << 7 << "\n"; 
} 
+1

आप कहीं और समस्या को आगे बढ़ा रहे हैं: अगर मैं इस कार्यक्रम को मारूं तो क्या होगा? जैसा लिखा है,^नियंत्रण कक्ष पर सी माता-पिता और बच्चे दोनों को एक सिगिनट भेज देगा। – BatchyX

+0

यह वास्तव में एक रचनात्मक उत्तर है (हालांकि इसमें टिप्पणीकर्ता-उल्लेखनीय मुद्दा है कि^सी दोनों हिट करेगा)। यदि आप चाहें तो आप^सी को अनदेखा कर सकते हैं, लेकिन आप^\ को अनदेखा नहीं कर पाएंगे। – IanPudney

1

मैं एक लिनक्स उपयोगकर्ता के रूप में जवाब दे रहा हूँ, लेकिन यह सब खिड़कियों पर लागू होना चाहिए।

मेरे पास ऐसा ही सवाल था, इसलिए उम्मीद है कि मैं पिछले उत्तरों को जोड़ सकता हूं और अपना दो सेंट जोड़ सकता हूं।

सिग्नल और abort(): ^C और ^Z बाहर निकलने से पहले अपने फ़ंक्शन को कॉल करने के लिए "अवरुद्ध" किया जा सकता है, संभवतः बाहर निकलने के साथ()। संकेत SIGQUIT AKA ^\ और SIGKILL जिनके पास कोई महत्वपूर्ण स्ट्रोक नहीं है, को अवरुद्ध नहीं किया जा सकता है। csignal शीर्षलेख और सी ++ लैम्ब्डा का उपयोग करने के लिए यहां एक उदाहरण दिया गया है।

#include <iostream> 
#include <csignal> 
#include <cstdlib> 

using namespace std; 

int main() 
{ 
    //signal requires lam take an int parameter 
    //this parameter is equal to the signals value 
    auto lam = 
     [] (int i) { cout << "aborting" << endl; exit(0); }; 

    //^C 
    signal(SIGINT, lam); 
    //abort() 
    signal(SIGABRT, lam); 
    //sent by "kill" command 
    signal(SIGTERM, lam); 
    //^Z 
    signal(SIGTSTP, lam); 


    while(1) 
    { 
    } 

    return 0; 
} 

बाहर निकलें: जब से मैं ऊपर मेरी उदाहरण में exit() इस्तेमाल किया, ध्यान यहाँ लिया जाना चाहिए। यदि फ़ंक्शन चल रहा है तो एक क्लीन-अप फ़ंक्शन है जिसे केवल एक बार चलाने की आवश्यकता है, शायद एक स्थिर चर has_run का उपयोग किया जा सकता है। या उपर्युक्त उदाहरण में, raise() एक संकेत है कि आप अवरुद्ध नहीं कर सकते हैं। लेकिन वे कोर डंप के साथ आते हैं जो सिर्फ गंदा महसूस करते हैं। आपकी पसंद, यहाँ। एक उदाहरण है कि C++ 11 एक quick_exit जो एक साथ at_quick_exit जो ऊपर के रूप में ही कार्य है जोड़ा

#include <cstdlib> 
#include <iostream> 

using namespace std; 

int main() 
{ 
    //called with no parameters 
    auto lam = []() { cout << "at exit"; }; 

    atexit(lam); 

    return 0; 
} 

लें टिप्पणी इस प्रकार है।लेकिन quick_exit के साथ कोई साफ-सफाई कार्य नहीं किया जाता है। इसके विपरीत, exit ऑब्जेक्ट विनाशकों के साथ कहा जाता है और सी धाराएं बंद होती हैं, केवल स्वचालित स्टोरेज वेरिएबल साफ़ नहीं हो जाते हैं।