सबसे पहले: मुझे पता है कि अधिक अनुकूलन बग प्रोग्रामिंग त्रुटियों के कारण हैं या उन तथ्यों पर भरोसा करते हैं जो अनुकूलन सेटिंग्स (फ़्लोटिंग पॉइंट मान, मल्टीथ्रेडिंग समस्याएं, ...) के आधार पर बदल सकते हैं।अनुकूलक बग या प्रोग्रामिंग त्रुटि?
हालांकि मुझे बग खोजने के लिए बहुत मुश्किल लग रही है और कुछ हद तक अनिश्चित है अगर ऑप्टिमाइज़ेशन बंद किए बिना इन तरह की त्रुटियों को रोकने से रोकने का कोई तरीका है। क्या मैं कुछ भूल रहा हूँ? क्या यह वास्तव में एक अनुकूलक बग हो सकता है? यहां एक सरलीकृत उदाहरण दिया गया है:
struct Data {
int a;
int b;
double c;
};
struct Test {
void optimizeMe();
Data m_data;
};
void Test::optimizeMe() {
Data * pData; // Note that this pointer is not initialized!
bool first = true;
for (int i = 0; i < 3; ++i) {
if (first) {
first = false;
pData = &m_data;
pData->a = i * 10;
pData->b = i * pData->a;
pData->c = pData->b/2;
} else {
pData->a = ++i;
} // end if
} // end for
};
int main(int argc, char *argv[]) {
Test test;
test.optimizeMe();
return 0;
}
पाठ्यक्रम के वास्तविक कार्यक्रम के मुकाबले बहुत कुछ करना है। लेकिन यह सब इस तथ्य से उबाल जाता है कि सीधे m_data तक पहुंचने के बजाय, एक (पहले प्रारंभिक) पॉइंटर का उपयोग किया जा रहा है।
if (first) {
first = false;
// pData-assignment has been removed!
m_data.a = i * 10;
m_data.b = i * m_data.a;
m_data.c = m_data.b/m_data.a;
} else {
pData->a = ++i; // This will crash - pData is not set yet.
} // end if
आप देख सकते हैं, यह करने के लिए एक सीधा लिखने के साथ अनावश्यक संकेतक भिन्नता की जगह: जैसे ही मैं if (first)
भाग के लिए पर्याप्त बयान जोड़ने के रूप में, अनुकूलक इन पंक्तियों के साथ कुछ करने के लिए कोड को बदलने के लिए लगता है सदस्य संरचना हालांकि यह else
-branch में ऐसा नहीं करता है। यह pData
-असाइनमेंट को भी हटा देता है। चूंकि सूचक अब भी प्रारंभिक है, इसलिए प्रोग्राम else
-branch में क्रैश हो जाएगा।
बेशक वहाँ विभिन्न चीजें हैं जो यहाँ सुधार किया जा सकता है, इसलिए आप प्रोग्रामर पर यह दोष हो सकता है:
- सूचक के बारे में भूल जाओ और कर क्या अनुकूलक करता है - सीधे
m_data
का उपयोग करें। - pdata को nullptr में प्रारंभ करें - इस तरह ऑप्टिमाइज़र जानता है कि
else
- अगर पॉइंटर कभी असाइन नहीं किया जाता है तो ब्रंच विफल हो जाएगा। कम से कम ऐसा लगता है कि मेरे परीक्षण-पर्यावरण में समस्या का समाधान हो रहा है। - लूप के सामने सूचक असाइनमेंट को ले जाएं (प्रभावी रूप से
pData
को&m_data
के साथ प्रारंभ करना, जो तब सूचक के बजाय एक संदर्भ (अच्छे उपाय के लिए) भी हो सकता है। यह समझ में आता है क्योंकि सभी मामलों में पीडीएटी की आवश्यकता है इसलिए कोई नहीं है कारण कोड स्पष्ट रूप से बदबूदार है पाश अंदर यह करने के लिए
, कम से कम कहने के लिए है, और मैं ऐसा करने के लिए अनुकूलक "दोष" करने की कोशिश कर नहीं कर रहा हूँ लेकिन मैं पूछ रहा हूँ:।। क्या कर रहा हूँ मैं गलत कर रहा हूं? कार्यक्रम बदसूरत हो सकता है, लेकिन यह वैध कोड है ...
मुझे यह जोड़ना चाहिए कि मैं वी +2012 का उपयोग कर रहा हूं सी + +/सीएलआई और v110_xp-Toolset। अनुकूलन/ओ 2 पर सेट है। कृपया यह भी ध्यान दें कि यदि आप वास्तव में समस्या को पुन: उत्पन्न करना चाहते हैं (हालांकि यह वास्तव में इस प्रश्न का मुद्दा नहीं है) तो आपको प्रोग्राम की जटिलता के साथ खेलने की आवश्यकता है। यह एक बहुत ही सरल उदाहरण है और ऑप्टिमाइज़र कभी-कभी सूचक असाइनमेंट को नहीं हटाता है। किसी फ़ंक्शन के पीछे &m_data
छिपाना "सहायता" लगता है।
संपादित करें:
प्रश्न: मुझे कैसे पता चलेगा कि संकलक उदाहरण की तरह कुछ करने के लिए अनुकूलन है प्रदान की?
एक: मैं कोडांतरक पढ़ने में बहुत अच्छा नहीं हूँ, मैं, लेकिन यह पर ध्यान दिया है और 3 टिप्पणियों जो मुझे विश्वास है कि यह इस तरह से व्यवहार कर रहा है बनाने के बना दिया है: में अनुकूलन किक के रूप में जैसे ही
- (अधिक असाइनमेंट जोड़ना आमतौर पर चाल करता है) सूचक असाइनमेंट में कोई असेंबलर कथन नहीं होता है। इसे घोषणा के लिए भी स्थानांतरित नहीं किया गया है, इसलिए यह वास्तव में अनियंत्रित छोड़ दिया गया है (कम से कम मेरे लिए)।
- ऐसे मामलों में जहां प्रोग्राम क्रैश हो जाता है, डीबगर असाइनमेंट स्टेटमेंट छोड़ देता है। ऐसे मामलों में जहां प्रोग्राम बिना किसी समस्या के चलता है, डीबगर वहां रुक जाता है।
- अगर मैं
pData
की सामग्री औरm_data
की सामग्री को देखने, जबकि डीबगिंग, यह स्पष्ट रूप से पता चलता है कि -branchm_data
औरm_data
पर एक प्रभाव हैif
में सभी कार्य सही मान प्राप्त करता है। पॉइंटर स्वयं यह अभी भी शुरुआत से ही उसी अनियमित मूल्य को इंगित करता है। इसलिए मुझे यह मानना है कि वास्तव में यह असाइनमेंट करने के लिए पॉइंटर का उपयोग नहीं कर रहा है।
प्रश्न: क्या मुझे (लूप अनोलिंग) के साथ कुछ भी करना है?
ए: नहीं, वास्तविक प्रोग्राम वास्तव में {...} जबकि() को SQL चयन-परिणामसेट पर लूप करने के लिए उपयोग करता है, इसलिए पुनरावृत्ति गणना पूरी तरह से रनटाइम-विशिष्ट है और संकलक द्वारा पूर्व निर्धारित नहीं किया जा सकता है।
इसे [एसएससीसीई] (http://sscce.org) में कम करें। – djechlin
@ डीजेक्लिन: अनुकूलन से प्रभावित कीड़े छोटे कोड नमूने को कम करना मुश्किल हो सकता है। सवाल स्पष्ट रूप से बताता है कि यह पहले से ही एक सरल उदाहरण है। –
अभी तक एक विचार स्पष्ट रूप से समझा नहीं सकता है, लेकिन क्या यह संरचना के बजाय कक्षा बनाने के समान ही काम करता है? – evilruff