2010-10-29 8 views
8

मैं C++ एक पुनरावर्ती समारोह के भीतर वर्तमान गहराई कैसे मिल सकता है की गहराई मिल सकती है? यानी यह जानना संभव है कि स्तर को ट्रैक रखने के लिए पैरामीटर का उपयोग किए बिना फ़ंक्शन को कितनी बार बुलाया गया था और उस नंबर को प्रत्येक बार फ़ंक्शन कहलाते समय पैरामीटर के रूप में पास किया गया था?मैं कैसे पिछले स्तर में गुजर बिना सी में एक पुनरावर्ती समारोह ++

उदाहरण के लिए मेरी पुनरावर्ती क्रिया इस तरह दिखता है:

DoSomething(int level) 
{ 
    print level; 
    if (level > 10) 
    return; 
    DoSomething(++level); 
} 

main 
{ 
    DoSomething(0); 
} 
+1

आप [इस चर्चा] पर एक नज़र रखना चाहते हैं (http://stackoverflow.com/questions/582673/is-there-a-cheaper-way-to-find-the-depth-of-the- कॉल-ढेर से अधिक का उपयोग कर-पश्व-अनुरेखन)। निचली पंक्ति यह है कि बैकट्रैक प्राप्त करने और इसका उपयोग करने के लिए एक कंपाइलर/मंच विशिष्ट तरीका हो सकता है ... लेकिन यह स्पष्ट रूप से बहुत संकलक/मंच विशिष्ट है और शायद इनलाइनिंग जैसी चीजों के लिए अतिसंवेदनशील है। किसी भी घटना में, एक नजर लायक हो सकता है। –

उत्तर

11

जवाब पहले से ही पर बिल्डिंग JoshD द्वारा दिए गए:

void recursive() 
{ 
    static int calls = 0; 
    static int max_calls = 0; 
    calls++; 
    if (calls > max_calls) 
     max_calls = calls; 

    recursive(); 

    calls--; 
} 

यह काउंटर रीसेट करता है पुनरावर्ती क्रिया पूरा हो गया है, लेकिन अभी भी प्रत्यावर्तन की अधिकतम गहराई पटरियों के बाद।

मैं कुछ भी करने के लिए इस तरह स्थैतिक चर का उपयोग नहीं होगा, लेकिन एक त्वरित परीक्षण के तुरंत बाद हटाए जाने के लिए। यदि आपको वास्तव में इसे चालू आधार पर ट्रैक करने की आवश्यकता है तो बेहतर तरीके हैं।

3

यदि आप धागे की सुरक्षा के बारे में परवाह नहीं है, एक स्थानीय स्थिर चर का उपयोग कर सकते हैं।

हालांकि, यह केवल आप एक उचित गिनती पहली बार जब आप अपने पुनरावर्ती दिनचर्या चलाने दे देंगे। एक बेहतर तकनीक एक आरएआईआई गार्ड-टाइप क्लास होगी जिसमें आंतरिक स्थैतिक चर शामिल है। रिकर्सिव रूटीन की शुरुआत में, गार्ड क्लास का निर्माण करें। कन्स्ट्रक्टर आंतरिक स्थैतिक चर को बढ़ाएगा, और विनाशक इसे कम करेगा। इस तरह, जब आप एक नया स्टैक-फ्रेम बनाते हैं तो काउंटर वृद्धि एक करके होती है, और जब आप प्रत्येक स्टैक-फ्रेम से वापस आते हैं तो काउंटर एक से कम हो जाएगा।

struct recursion_guard 
{ 
    recursion_guard() { ++counter; } 

    ~recursion_guard() { --counter; } 

    static int counter; 
}; 

int recursion_guard::counter = 0; 

void recurse(int x) 
{ 
    recursion_guard rg; 
    if (x > 10) return; 
    recurse(x + 1); 
} 

int main() 
{ 
    recurse(0); 
    recurse(0); 
} 

नोट हालांकि, यह अभी भी थ्रेड-सुरक्षित नहीं है। आप धागे की सुरक्षा की जरूरत है, आप एक धागे की स्थानीय भंडारण चर के साथ स्थिर भंडारण चर जगह ले सकता है या तो boost::thread_specific_ptr का उपयोग कर या C++ 0x धागा स्थानीय सुविधाओं।

+0

मैं इस तरह कुछ सोच रहा था, लेकिन आप मुझे इसे हराया। आपको ध्यान रखना चाहिए कि गार्ड-क्लास में अभी भी थ्रेड-सुरक्षित नहीं होने की समस्या है। –

+0

@ मार्क रान्ससम, सच। एक मूर्ख-सबूत सुधार स्थिर-भंडारण चर को थ्रेड-लोकल-स्टोरेज वैरिएबल के साथ प्रतिस्थापित करना होगा, या तो 'boost :: thread_specific_ptr' या C++ 0x थ्रेड स्थानीय सुविधाओं का उपयोग कर। –

5

आप समारोह में एक स्थिर चर का उपयोग कर सकते हैं ...

void recursive() 
{ 
static int calls = 0; 
calls++; 
recursive(); 
} 
बेशक

, इस गिनती रखना होगा जब आप एक नया प्रारंभिक कॉल प्रारंभ ....

+0

हां यह एक समस्या है। मैं कॉल कैसे रीसेट करूं? – Arizona1911

+1

यह भी पुनः प्रवेश या थ्रेड-सुरक्षित नहीं होगा। –

0

परिवर्तित level एक नई वस्तु (आमतौर पर एक टेम्पलेट) तर्क और (संभवतः) समारोह युक्त करने में सक्षम का एक उदाहरण चर के लिए। तो आप रिकर्सन संचयक इंटरफ़ेस का पुन: उपयोग कर सकते हैं।

0

तुम भी गहराई लॉग इन करने के लिए एक वैश्विक चर का उपयोग कर की कोशिश कर सकते हैं।

var depth = 0; 

DoSomething() 
{ 
    print ++depth; 
    if (depth > 10) 
    return; 
    DoSomething(); 
} 

main 
{ 
    DoSomething(0); 
} 
+1

एक वैश्विक लूजर स्कोप के साथ सिर्फ एक स्थिर है। –

+1

मैं कहूंगा कि एक स्थिर वास्तव में एक वैश्विक है <। < – Blindy

1

यदि आप संकलन समय पर निर्धारित किए जा सकते हैं, तो आप टेम्पलेट पैरामीटर के रूप में स्तर को भी पास कर सकते हैं। आप फ़ंक्शन ऑब्जेक्ट का भी उपयोग कर सकते हैं। यह सबसे अच्छा विकल्प दूर और दूर है - कम परेशानी, और यथासंभव स्थिर चर से बचा जाना चाहिए।

struct DoSomething { 
    DoSomething() { 
     calls = 0; 
    } 
    void operator()() { 
     std::cout << calls; 
     calls++; 
     if (calls < 10) 
      return operator()(); 
     return; 
    } 
    int calls; 
}; 

int main() { 
    DoSomething()(); // note the double(). 
    std::cin.get(); 
} 
2

यदि आप चाहते हैं कि उसे करने के लिए हो सकता है फिर से प्रवेशी और धागे की सुरक्षित, क्यों नहीं:

void rec(int &level) // reference to your level var 
{ 
    // do work 

    rec(++level); // go down one level 
} 

main() 
{ 
    //and you call it like 
    int level=0; 
    rec(level); 

    cout<<level<<" levels."<<endl; 
} 

गंदगी सूत्रण के लिए कोई स्थिर/वैश्विक चर और आप अलग अलग के लिए विभिन्न चर का उपयोग कर सकते हैं पुन: प्रवेश के मुद्दों के लिए रिकर्सिव चेन।

+0

मुझे यह पसंद है – Fihop

+0

हाँ मेरे पास वैश्विक चर के बारे में कुछ बात है (जो 'स्थिर' एक प्रकार का है) जब एक सामान्य स्टैक-आधारित चर करेगा। – Blindy

संबंधित मुद्दे