2012-01-24 18 views
6

निम्नलिखित कोड पर विचार करें साथ unordered_map देखने:बचें temporaries :: std :: स्ट्रिंग कुंजी

std::map<std::string, int> m1; 
auto i = m1.find("foo"); 

const char* key = ... 
auto j = m1.find(key); 

यह हर नक्शा देखने के लिए एक अस्थायी std :: स्ट्रिंग वस्तु का निर्माण करेगा। इससे बचने के लिए कैननिक तरीके क्या हैं?

+1

यदि आप मानचित्र की परिभाषा को बदल सकते हैं, तो आप एक कस्टम तुलनित्र का उपयोग कर सकते हैं जो 'char const *' सीधे – Pablo

+0

कहां देता है आपको 'कॉन्स्ट char * 'कहां मिलेगा? – Puppy

+0

@Pablo: लेकिन फिर .. किसी को एक स्मृति जहां उन कुंजियों को इंगित कर रहे हैं का प्रबंधन करने के .. जब तक वे डेटा खंड ... –

उत्तर

3

पॉइंटर्स का उपयोग न करें; इसके बजाय, स्ट्रिंग सीधे पास करें। तो फिर तुम संदर्भ का लाभ ले सकते:

void do_something(std::string const & key) 
{ 
    auto it = m.find(key); 
    // .... 
} 

सी ++ आम तौर पर हो जाता है "और अधिक सही" जितना अधिक आप अपने मुहावरे का उपयोग करें और इसके साथ सी लिखने की कोशिश नहीं करते।

+1

... जब तक आपको वास्तव में सी लिखने की आवश्यकता नहीं है, लेकिन फिर .. आपको सी ++ की आवश्यकता क्यों है? :- डी –

+0

हालांकि यह 'm1.find ("foo") को संबोधित नहीं करता है,' अस्थायी ऑब्जेक्ट समस्या बना रहा है (भले ही, यह अस्थायी रूप से बाधित नहीं किया जा सकता है)। –

+2

मैं पॉइंटर्स का उपयोग करने से नहीं बच सकता। मैं एक मूल्य के लिए खोज करता हूं जो बाहरी स्रोत से सी स्ट्रिंग के रूप में आता है। इसका अभी भी मतलब है कि मुझे प्रत्येक लुकअप के लिए एक स्ट्रिंग बनाना है। –

0

अच्छा, मानचित्र का find वास्तव में कुंजी के निरंतर संदर्भ को स्वीकार करता है, इसलिए आप इसे एक बिंदु या दूसरे पर बनाने से नहीं बच सकते हैं।

कोड के पहले भाग के लिए आप निरंतर स्थैतिक std :: स्ट्रिंग को "foo" मान के साथ देख सकते हैं। इस तरह आप प्रतियां नहीं बनाएंगे।

यदि आप स्पार्टन के रास्ते पर जाना चाहते हैं, तो आप हमेशा अपना स्वयं का प्रकार बना सकते हैं जिसे स्ट्रिंग की तरह इस्तेमाल किया जा सकता है, लेकिन स्ट्रिंग अक्षर को पॉइंटर भी पकड़ सकता है।

लेकिन किसी भी घटना में, मानचित्र लुकअप से जुड़े ओवरहेड इतने विशाल हैं कि यह वास्तव में समझ में नहीं आता है। अगर मैं आप थे तो मैं पहले Google के घने हैश के साथ मानचित्र/unordered_map को प्रतिस्थापित करूंगा। तब मैं इंटेल के वीट्यून (इन दिनों एम्पलीफायर) चलाऊंगा और देख सकता हूं कि समय कहां जा रहा है और उन स्थानों को अनुकूलित करें। मुझे तारों पर संदेह है क्योंकि कुंजी एक बाधा शीर्ष दस सूची में दिखाई देगी।

+0

मुझे कुछ याद आना चाहिए, लेकिन स्पार्टन कौन है? – Cameron

+1

@ कैमरॉन: मुझे विश्वास है कि वह एजियन सी कंपाइलर के लेखक हैं। बहुत मितव्ययी और मेहनती। –

0

llvm से StringRef कक्षा पर एक नज़र डालें।

उन्हें सी-तार, स्ट्रिंग अक्षर या std :: स्ट्रिंग से बहुत सस्ता बनाया जा सकता है। यदि आपने std :: स्ट्रिंग के बजाय उन लोगों का नक्शा बनाया है, तो निर्माण बहुत तेज़ होगा।

हालांकि यह एक बहुत ही नाजुक प्रणाली है। आपको यह सुनिश्चित करने की ज़रूरत है कि आपके द्वारा डाले गए तारों का जो भी स्रोत नक्शा के जीवनकाल के लिए जिंदा और असम्बद्ध रहता है।

0

आप std::map एक कस्टम तुलनित्र वर्ग देकर अस्थायी से बच सकते हैं, जो char * एस की तुलना कर सकते हैं। (डिफ़ॉल्ट, सूचक के पते का उपयोग करेगा जो है कि तुम क्या नहीं चाहते हैं तो आप स्ट्रिंग के मूल्य पर की तुलना करने की जरूरत है।।)

इस प्रकार, कुछ की तरह:

class StrCmp 
{ 
public: 
    bool operator() (const char *a, const char *b) 
    { 
    return strcmp(a, b) < 0; 
    } 
}; 

// Later: 
std::map<const char *, int, StrCmp> m; 

फिर, एक सामान्य मानचित्र की तरह उपयोग करें , लेकिन चार * पास पास करें। ध्यान रखें कि मानचित्र में संग्रहीत कुछ भी मानचित्र की अवधि के लिए जीवित रहना चाहिए। इसका मतलब है कि आपको चार अक्षर की आवश्यकता है, या आपको अपने आप को पॉइंटर द्वारा इंगित डेटा को रखना होगा। इन कारणों से, मैं std::map<std::string> के साथ जाऊंगा और अस्थायी खाने तक प्रोफाइलिंग दिखाता हूं कि ऊपर की वास्तव में आवश्यकता थी।

+0

डाउनवॉटर के लिए: दिमाग आपके डाउनवोट को समझाता है? – Thanatos

1

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

हालांकि, यदि आपको लगातार आधार पर सी-स्टाइल स्ट्रिंग को प्रॉक्सी करने की आवश्यकता है, तो भी आप कस्टम समाधान के साथ आ सकते हैं जो इस आवंटन को पास कर देगा।यदि आपको यह वास्तव में करना है तो यह भुगतान कर सकता है और आपके तार छोटे स्ट्रिंग अनुकूलन से लाभ नहीं लेते हैं।

आप केवल स्ट्रिंग कार्यक्षमता (जैसे ही काम और प्रतियां) की एक बहुत छोटे सबसेट की जरूरत है, तो आप एक छोटे से विशेष प्रयोजन स्ट्रिंग वर्ग है कि एक const char * सूचक और स्मृति जारी करने के लिए एक समारोह संग्रहीत करता है लिख सकते हैं। जैसे std::string करता चरित्र बफर की एक प्रति का निर्माण नहीं करता

std::map<cheap_string, int> m1; 
auto i = m1.find(cheap_string::proxy("foo")); 

अस्थायी cheap_string उदाहरण, फिर भी यह के उदाहरण के भंडारण के लिए सुरक्षित प्रतिलिपि अर्थ विज्ञान को बरकरार रखता है:

class cheap_string 
{ 
public: 
    typedef void(*Free)(const char*); 
private: 
    const char * myData; 
    std::size_t mySize; 
    Free myFree; 
public: 
    // direct member assignments, use with care. 
    cheap_string (const char * data, std::size_t size, Free free); 

    // releases using custom deleter (a no-op for proxies). 
    ~cheap_string(); 

    // create real copies (safety first). 
    cheap_string (const cheap_string&); 
    cheap_string& operator= (const cheap_string&); 
    cheap_string (const char * data); 
    cheap_string (const char * data, std::size_t size) 
     : myData(new char[size+1]), mySize(size), myFree(&destroy) 
    { 
     strcpy(myData, data); 
     myData[mySize] = '\0'; 
    } 

    const char * data() const; 
    const std::size_t size() const; 

    // whatever string functionality you need. 
    bool operator< (const cheap_string&) const; 
    bool operator== (const cheap_string&) const; 

    // create proxies for existing character buffers. 
    static const cheap_string proxy (const char * data) 
    { 
      return cheap_string(data, strlen(data), &abandon); 
    } 

    static const cheap_string proxy (const char * data, std::size_t size) 
    { 
      return cheap_string(data, size, &abandon); 
    } 

private: 
    // deleter for proxies (no-op) 
    static void abandon (const char * data) 
    { 
     // no-op, this is used for proxies, which don't own the data! 
    } 

    // deleter for copies (delete[]). 
    static void destroy (const char * data) 
    { 
     delete [] data; 
    } 
}; 

उसके बाद, आप के रूप में इस वर्ग का उपयोग कर सकते मानक कंटेनरों में cheap_string

नोटों: यदि आपके कार्यान्वयन वापसी मान अनुकूलन का उपयोग नहीं करता है, आप इस तरह के एक विशेष अधिभार के साथ एक निर्माता के रूप में proxy विधि के लिए एक वैकल्पिक वाक्य रचना, ढूंढना चाहेंगे (ए ला std::nothrow के लिए एक कस्टम proxy_t प्रकार लेने प्लेसमेंट नया)।

+0

... लेकिन 'cheap_string' की आपकी परिभाषा के अनुसार, क्या यह अस्थायी हटा दिए जाने के बाद' गलत तरीके से) "गलत" करने की कोशिश नहीं करेगा? – Thanatos

+0

नहीं, क्योंकि 'प्रॉक्सी()' विधि कस्टम डिलीटर 'त्याग() 'का उपयोग करती है जो एक नो-ऑप है जिसे कभी भी कॉल नहीं किया जाता है। मुझे विस्तार से बताएं। –

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