मैंने अपने जीवन के तीन दिन खो दिए हैं, एक बहुत ही अजीब बग को ट्रैक करना है जहाँ unordered_map :: सम्मिलित करना () आपके द्वारा डाले गए चर को नष्ट कर देता है। यह अत्यधिक गैर-स्पष्ट व्यवहार केवल हाल ही के संकलक में होता है: मैंने पाया कि 3.2-3.4 और जीसीसी 4.8 इस "सुविधा" को प्रदर्शित करने के लिए केवल संकलक हैं।
यहाँ मेरे मुख्य कोड आधार से कुछ कम कोड है जो समस्या को प्रदर्शित करता है:
#include <memory>
#include <unordered_map>
#include <iostream>
int main(void)
{
std::unordered_map<int, std::shared_ptr<int>> map;
auto a(std::make_pair(5, std::make_shared<int>(5)));
std::cout << "a.second is " << a.second.get() << std::endl;
map.insert(a); // Note we are NOT doing insert(std::move(a))
std::cout << "a.second is now " << a.second.get() << std::endl;
return 0;
}
मैं, शायद अधिकांश C ++ प्रोग्रामर की तरह, आउटपुट से कुछ इस तरह दिखने की उम्मीद करेंगे:
a.second is 0x8c14048
a.second is now 0x8c14048
लेकिन क्लैंग 3.2-3.4 और जीसीसी 4.8 के साथ मुझे इसके बजाय मिलता है:
a.second is 0xe03088
a.second is now 0
जिसका कोई मतलब नहीं है, जब तक कि आप unordered_map :: डालने () के लिए http://www.cplusplus.com/reference/unordered_map/unordered_map/insert/ पर करीब से जांच न करें, जहां ओवरलोड नंबर 2 है:
template <class P> pair<iterator,bool> insert ( P&& val );
जो एक लालची सार्वभौमिक संदर्भ चाल अधिभार है, जो किसी भी चीज को अन्य अधिभार से मेल नहीं खाता है, और इसका निर्माण एक value_type में ले जाता है। तो ऊपर दिए गए हमारे कोड ने इस अधिभार को क्यों चुना, और न कि unordered_map :: value_type अधिभार के रूप में शायद सबसे अधिक उम्मीद होगी?
उत्तर आपको चेहरे पर घूरता है: unordered_map :: value_type एक जोड़ी है < const int, std :: साझा_ptr > और कंपाइलर सही ढंग से सोचेंगे कि एक जोड़ी < int , std :: साझा_ptr> संभव नहीं है। इसलिए संकलक चाल सार्वभौमिक संदर्भ अधिभार को चुनता है, और जो प्रोग्रामर को std :: move () का उपयोग नहीं करने के बावजूद मूल को नष्ट कर देता है, जो यह संकेत देने के लिए विशिष्ट सम्मेलन है कि आप एक चर नष्ट होने के साथ ठीक हैं। इसलिए डालने को नष्ट करने वाला व्यवहार वास्तव में C ++ 11 मानक के अनुसार सही है , और पुराने संकलक गलत थे ।
आप शायद देख सकते हैं कि इस बग के निदान में मुझे तीन दिन क्यों लगे। यह एक बड़े कोड बेस में बिल्कुल स्पष्ट नहीं था, जहां टाइप किया जा रहा है unordered_map में टाइप किए गए स्रोत कोड की शर्तों में बहुत दूर परिभाषित किया गया था, और यह जांचने के लिए किसी के साथ कभी नहीं हुआ कि क्या टाइपडिफ value_type के समान था।
इसलिए मेरे सवालों को ढेर करने के लिए:
पुराने संकलक नए संकलक की तरह डाले गए चरों को नष्ट नहीं करते हैं? मेरा मतलब है, यहां तक कि GCC 4.7 ऐसा नहीं करता है, और यह सुंदर मानकों के अनुरूप है।
क्या इस समस्या को व्यापक रूप से जाना जाता है, क्योंकि निश्चित रूप से अपग्रेडिंग कम्पाइलर कोड का कारण बनेंगे जो अचानक काम करना बंद कर देते थे?
क्या C ++ मानक समिति ने इस व्यवहार का इरादा किया था?
आप यह कैसे सुझाएंगे कि unordered_map :: प्रविष्टि () को बेहतर व्यवहार देने के लिए संशोधित किया जाए? मैं यह पूछता हूं क्योंकि अगर यहां समर्थन है, तो मैं इस व्यवहार को डब्ल्यूजी 21 को एन नोट के रूप में प्रस्तुत करने का इरादा रखता हूं और उनसे बेहतर व्यवहार को लागू करने के लिए कहता हूं।
4.9.0 20131223 (experimental)
क्रमशः gcc 4.8.2 और क्रमशः उपयोग कर रहा हूं । a.second is now 0x2074088
मेरे लिए आउटपुट (या समान) है।
a
नहीं है। इसकी एक प्रति बनानी चाहिए। इसके अलावा, यह व्यवहार पूरी तरह से stdlib पर निर्भर करता है, संकलक पर नहीं।