2010-10-25 4 views
8

मैंने एक साधारण परीक्षण केस बनाया है जो मैंने देखा है कि एक बड़े कोड बेस में मैंने देखा है कि एक अजीब व्यवहार का प्रदर्शन किया है। यह टेस्ट केस नीचे है। मैं ऐसे structs के मानचित्र में एक संरचना के लिए सूचक बनाने के लिए एसटीएल मानचित्र के "[]" ऑपरेटर पर भरोसा कर रहा हूं। नीचे दिए गए टेस्ट केस में, लाइन ...एक एसटीएल में structs के मानचित्र, "[]" ऑपरेटर क्यों संरचना के dtor 2 अतिरिक्त बार बुलाया जाता है?

TestStruct *thisTestStruct = &testStructMap["test"]; 

... मुझे पॉइंटर प्राप्त करता है (और मानचित्र में एक नई प्रविष्टि बनाता है)। मैंने देखा है कि अजीब चीज यह है कि यह लाइन न केवल नक्शा में एक नई प्रविष्टि का कारण बनती है ("[]" ऑपरेटर की वजह से), लेकिन किसी कारण से यह संरचना के विनाशक को दो अतिरिक्त बार कहा जाता है। मुझे कुछ याद आ रहा है - किसी भी मदद की बहुत सराहना की है! धन्यवाद!

#include <iostream> 
#include <string> 
#include <map> 

using namespace std; 
struct TestStruct; 

int main (int argc, char * const argv[]) { 

    map<string, TestStruct> testStructMap; 

    std::cout << "Marker One\n"; 

    //why does this line cause "~TestStruct()" to be invoked twice? 
    TestStruct *thisTestStruct = &testStructMap["test"]; 

    std::cout << "Marker Two\n"; 

    return 0; 
} 

struct TestStruct{ 
    TestStruct(){ 
     std::cout << "TestStruct Constructor!\n"; 
    } 

    ~TestStruct(){ 
     std::cout << "TestStruct Destructor!\n"; 
    } 
}; 

कोड ऊपर आउटपुट निम्नलिखित ...

/* 
Marker One 
TestStruct Constructor!    //makes sense 
TestStruct Destructor!    //<---why? 
TestStruct Destructor!    //<---god why? 
Marker Two 
TestStruct Destructor!    //makes sense 
*/ 

... लेकिन मुझे समझ नहीं आता क्या TestStruct नाशक के पहले दो आमंत्रण का कारण बनता है? (मुझे लगता है कि पिछले नाशक मंगलाचरण समझ में आता है क्योंकि testStructMap क्षेत्र से बाहर जा रहा है।)

+0

उत्तर नीचे दिया गया है। लेकिन ऑप्टिमाइज़ेशन स्तर जितना अधिक होगा उतना ही देखेंगे और देखें कि कितनी प्रतियां मिलती हैं। –

+0

इस प्रश्न के बारे में और जानकारी और इसके पीछे क्यों इस प्रश्न में पाया जा सकता है: https://stackoverflow.com/questions/26021118/why-doesnt-c-stdmapoperator-use-inplace-new – srm

उत्तर

18

std::map<>::operator[] की कार्यक्षमता बराबर है

को
(*((std::map<>::insert(std::make_pair(x, T()))).first)).second 

अभिव्यक्ति:

#include <iostream> 
#include <string> 
#include <map> 

using namespace std; 
struct TestStruct; 

int main (int argc, char * const argv[]) { 

    map<string, TestStruct> testStructMap; 

    std::cout << "Marker One\n"; 

    //why does this line cause "~TestStruct()" to be invoked twice? 
    TestStruct *thisTestStruct = &testStructMap["test"]; 

    std::cout << "Marker Two\n"; 

    return 0; 
} 

struct TestStruct{ 
    TestStruct(){ 
     std::cout << "TestStruct Constructor!\n"; 
    } 

    TestStruct(TestStruct const& other) { 
     std::cout << "TestStruct copy Constructor!\n"; 
    } 

    TestStruct& operator=(TestStruct const& rhs) { 
     std::cout << "TestStruct copy assignment!\n"; 
    } 

    ~TestStruct(){ 
     std::cout << "TestStruct Destructor!\n"; 
    } 
}; 

में परिणाम:

5

TestStruct के इंटरफ़ेस करने के लिए निम्नलिखित जोड़ें: map को

TestStruct(const TestStruct& other) { 
    std::cout << "TestStruct Copy Constructor!\n"; 
} 
4

operator[] आवेषण अगर वहाँ पहले से ही वहाँ एक भाग नहीं होता ।

जो आप खो रहे हैं वह आपके TestStruct में कंपाइलर-आपूर्ति प्रतिलिपि निर्माता के लिए आउटपुट है, जिसका उपयोग कंटेनर हाउसकीपिंग के दौरान किया जाता है। उस आउटपुट को जोड़ें, और इसे सभी को और अधिक समझना चाहिए।

संपादित करें: एंड्री के जवाब ने मुझे माइक्रोसॉफ्ट वीसी ++ 10 के <map> में स्रोत पर एक नज़र डालने के लिए प्रेरित किया, जो कि आप अपने सभी गोरियों के विवरण के माध्यम से इसका पालन करने के लिए कुछ भी कर सकते हैं। आप insert() कॉल देख सकते हैं जिसमें वह संदर्भित करता है।

mapped_type& operator[](const key_type& _Keyval) 
    { // find element matching _Keyval or insert with default mapped 
    iterator _Where = this->lower_bound(_Keyval); 
    if (_Where == this->end() 
     || this->comp(_Keyval, this->_Key(_Where._Mynode()))) 
     _Where = this->insert(_Where, 
      value_type(_Keyval, mapped_type())); 
    return ((*_Where).second); 
    } 
4

आपका दो रहस्यमय नाशक कॉल शायद प्रतिलिपि निर्माता कहीं चल रहा कॉल std::map भीतर के साथ रखा जाता है। उदाहरण के लिए, यह कल्पना की जा सकती है कि operator[] डिफ़ॉल्ट-अस्थायी TestStruct ऑब्जेक्ट बनाता है, और उसके बाद इसे मानचित्र में उचित स्थान पर कॉपी करता है। कारण है कि दो विनाशक कॉल (और इस प्रकार शायद दो प्रतिलिपि कन्स्ट्रक्टर कॉल) कार्यान्वयन-विशिष्ट है, और यह आपके कंपाइलर और मानक पुस्तकालय कार्यान्वयन पर निर्भर करेगा। भाषा के रूप में विनिर्दिष्ट

Marker One 
TestStruct Constructor! 
TestStruct copy Constructor! 
TestStruct copy Constructor! 
TestStruct Destructor! 
TestStruct Destructor! 
Marker Two 
TestStruct Destructor! 
8

आप कुछ अनदेखी प्रतियां बनाया जा रहा है विनिर्देश। यह, जैसा कि आप देख सकते हैं, T प्रकार की एक अस्थायी वस्तु को डिफॉल्ट-निर्माण करना शामिल है, इसे std::pair ऑब्जेक्ट में कॉपी करना, जिसे बाद में मानचित्र के नए तत्व में कॉपी किया गया है (माना जाता है कि यह पहले से नहीं था)।जाहिर है, यह कुछ मध्यवर्ती T वस्तुओं का उत्पादन करेगा। इन मध्यवर्ती वस्तुओं का विनाश वह है जो आप अपने प्रयोग में देखते हैं। आप उनके निर्माण को याद करते हैं, क्योंकि आप अपनी कक्षा के प्रति-निर्माता से कोई प्रतिक्रिया नहीं उत्पन्न करते हैं।

मध्यवर्ती वस्तुओं की सटीक संख्या संकलक अनुकूलन क्षमताओं पर निर्भर हो सकती है, इसलिए परिणाम भिन्न हो सकते हैं।

0

तो सबक है - यदि आप अपनी जीवनशैली की परवाह करते हैं तो मानचित्र में structs न रखें। पॉइंटर्स का उपयोग करें, या यहां तक ​​कि बेहतर साझा_ptrs उन्हें

0

आप इसे और अधिक सरल कोड के माध्यम से देख सकते हैं।

#include <iostream> 
#include <map> 

using namespace std; 

class AA 
{ 
public: 
    AA()   { cout << "default const" << endl; } 
    AA(int a):x(a) { cout << "user const" << endl; } 
    AA(const AA& a) { cout << "default copy const" << endl; } 
    ~AA()   { cout << "dest" << endl; } 
private: 
    int x; 
}; 

int main() 
{ 
    AA o1(1); 

    std::map<char,AA> mymap; 

    mymap['x']=o1; // (1) 

    return 0; 
} 

नीचे परिणाम से पता चलता है कि बनाता है ऊपर (1) लाइन कोड (1 डिफ़ॉल्ट स्थिरांक) और (2 डिफ़ॉल्ट प्रतिलिपि स्थिरांक) कहते हैं।

user const 
default const  // here 
default copy const // here 
default copy const // here 
dest 
dest 
dest 
dest 
संबंधित मुद्दे