2012-06-08 12 views
5

मैं ऐसे प्रोग्राम पर काम कर रहा हूं जो एक महत्वपूर्ण डेटा संरचना को प्रोग्राम-परिभाषित डिलीमीटर के साथ एक संरचित स्ट्रिंग के रूप में संग्रहीत करता है (इसलिए हमें स्ट्रिंग को चलाने और हमें आवश्यक जानकारी निकालने की आवश्यकता है हम जाते हैं) और हम इसे एक अधिक संरचित डेटा प्रकार में परिवर्तित करना चाहते हैं।एक आवंटन में एक स्ट्रिंग युक्त स्ट्रक्चर को आवंटित करें

संक्षेप में, इसमें एक फ़ील्ड के साथ एक स्ट्रक्चर की आवश्यकता होगी जिसमें वर्णन किया गया है कि किस प्रकार के डेटा में संरचना है और एक और फ़ील्ड जो डेटा के साथ स्ट्रिंग है। स्ट्रिंग की लंबाई हमेशा आवंटन समय पर जानी जाएगी। हमने परीक्षण के माध्यम से निर्धारित किया है कि इन डेटा प्रकारों में से प्रत्येक के लिए आवश्यक आवंटन की संख्या दोगुना करना एक अस्वीकार्य लागत है। संरचना के लिए स्मृति आवंटित करने का कोई तरीका है और एक आवंटन में संरचना में निहित std :: स्ट्रिंग है? अगर हम cstrings का उपयोग कर रहे थे तो मेरे पास संरचना में एक char * होगा और संरचना और स्ट्रिंग के लिए पर्याप्त ब्लॉक आवंटित करने के बाद इसे संरचना के अंत में इंगित करें, लेकिन यदि संभव हो तो हम std :: स्ट्रिंग को प्राथमिकता देंगे।

मेरा अधिकांश अनुभव सी के साथ है, इसलिए कृपया यहां प्रदर्शित किसी भी सी ++ अज्ञानता को क्षमा करें।

+0

यदि मैं इसे सही ढंग से समझता हूं, तो निर्माण के बाद स्ट्रिंग विकसित नहीं हो सकती है, और जो भी पूरी वस्तु का प्रबंधन करता है, उसकी स्मृति को प्रबंधित किया जाएगा ... क्योंकि आप सी रास्ता जा रहे हैं, क्यों न केवल 'char * 'का उपयोग करें? सी तारों के सबसे बुरे हिस्सों को स्मृति का प्रबंधन करने की आवश्यकता है, लेकिन ऐसा लगता है कि आपके मामले में यह कोई समस्या नहीं है, है ना? –

+3

+1 ** ** साबित करने के लिए ** सभी अर्ध-मुर्गा से बाहर जाने से पहले अनुकूलन की आवश्यकता! –

+0

यदि आप * वास्तव में * सी-स्ट्रिंग के बजाय 'std :: string' का उपयोग करने के इच्छुक हैं, तो आप जो कुछ करना चाहते हैं उसे प्राप्त करने के लिए कस्टम आवंटक का उपयोग करके देख सकते हैं। इससे आप अपने तारों को एक ही आवंटन में पूल करने की अनुमति दे सकते हैं, लेकिन फिर भी इसे एक ही समय में आवंटित सब कुछ (यानी आपकी संरचना) नहीं मिलेगा और यह शायद रखरखाव दुःस्वप्न होने का अंत हो जाएगा। शायद सी-तारों से चिपकने के लिए सबसे अच्छा है। –

उत्तर

1

यदि आपके पास ऐसी कठोर स्मृति आवश्यकताएं हैं, तो आपको std::string पर छोड़ना होगा।

सबसे अच्छा विकल्प find है या basic_string_ref (a proposal for the next C++ standard library) का कार्यान्वयन लिखें, जो वास्तव में एक आकार के साथ एक char * है। लेकिन इसमें std::basic_string के सभी (गैर-उत्परिवर्तनीय) फ़ंक्शन हैं। फिर आप अपनी इच्छित मेमोरी आवंटित करने के लिए फ़ैक्टरी फ़ंक्शन का उपयोग करते हैं (आपका स्ट्रक्चर आकार + स्ट्रिंग डेटा), और फिर basic_string_ref प्रारंभ करने के लिए प्लेसमेंट नया का उपयोग करें।

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


previously linked to implementation of basic_string_ref (और इससे संबंधित typedefs, string_ref) को देखते हुए यहां एक कारखाने निर्माता/नाशक, है कुछ प्रकार टी उस पर एक स्ट्रिंग की जरूरत है कि के लिए: जाहिर है

template<typename T> T *Create(..., const char *theString, size_t lenstr) 
{ 
    char *memory = new char[sizeof(T) + lenstr + 1]; 
    memcpy(memory + sizeof(T), theString, lenstr); 

    try 
    { 
    return new(memory) T(..., string_ref(theString, lenstr); 
    } 
    catch(...) 
    { 
    delete[] memory; 
    throw; 
    } 
} 

template<typename T> T *Create(..., const std::string & theString) 
{ 
    return Create(..., theString.c_str(), theString.length()); 
} 

template<typename T> T *Create(..., const string_ref &theString) 
{ 
    return Create(..., theString.data(), theString.length()); 
} 

template<typename T> void Destroy(T *pValue) 
{ 
    pValue->~T(); 

    char *memory = reinterpret_cast<char*>(pValue); 
    delete[] memory; 
} 

, आप ' आपको अन्य कन्स्ट्रक्टर पैरामीटर को भरने की आवश्यकता होगी।और आपके प्रकार के कन्स्ट्रक्टर को string_ref लेना होगा जो स्ट्रिंग को संदर्भित करता है।

1

यदि आप std::string का उपयोग कर रहे हैं, तो आप वास्तव में संरचना और स्ट्रिंग दोनों के लिए एक आवंटन नहीं कर सकते हैं, और आप दोनों को एक बड़ा ब्लॉक होने का आवंटन भी नहीं कर सकते हैं। यदि आप पुरानी सी-शैली तारों का उपयोग कर रहे हैं तो यह संभव है।

0

संक्षेप में, इसमें एक फ़ील्ड के साथ एक स्ट्रक्चर की आवश्यकता होगी जिसमें वर्णन किया गया है कि किस प्रकार के डेटा में संरचना है और एक और फ़ील्ड जो डेटा के साथ स्ट्रिंग है।

मुझे एहसास है कि आप सी ++ की टाइप-सिस्टम का अधिकतम क्षमता यहां शोषण नहीं कर रहे हैं। यह बहुत सी-आश दिखता है और महसूस करता है (यह एक उचित शब्द नहीं है, मुझे पता है)। मेरे यहां पोस्ट करने के लिए ठोस उदाहरण नहीं हैं क्योंकि मुझे उस समस्या के बारे में कोई जानकारी नहीं है जिसे आप हल करने का प्रयास कर रहे हैं।

क्या एक आवंटन में संरचना में निहित संरचना और std :: स्ट्रिंग के लिए स्मृति आवंटित करने का कोई तरीका है?

मेरा मानना ​​है कि आप संरचना आवंटन के लिए स्ट्रिंग की एक प्रति के बाद संरचना आवंटन के बारे में चिंता कर रहे हैं? यह आदर्श नहीं होना चाहिए (लेकिन बेशक, यह इस बात पर निर्भर करता है कि आप कैसे और कब सदस्यों को प्रारंभ कर रहे हैं)। सी ++ 11 निर्माण निर्माण का समर्थन करता है। यह किसी भी अतिरिक्त स्ट्रिंग प्रतियों का ख्याल रखना चाहिए जिनके बारे में आप चिंतित हैं।

आप सच में, सच कुछ कोड इस चर्चा सार्थक :)

कार्यक्रम से परिभाषित सीमांकक

एक सवाल के साथ एक असंरचित स्ट्रिंग के रूप में एक महत्वपूर्ण डेटा संरचना बनाने के लिए पोस्ट करना चाहिए: इस स्ट्रिंग है परिवर्तनशील? यदि नहीं, तो आप थोड़ा अलग डेटा-संरचना का उपयोग कर सकते हैं। इस महत्वपूर्ण डेटा संरचना के हिस्सों की प्रतियों को संग्रहित न करें बल्कि इस स्ट्रिंग के लिए इंडेक्स/इटरेटर जो डिलीमीटर को इंगित करते हैं।

// assume that !, [, ], $, % etc. are your program defined delims 
const std::string vital = "!id[thisisdata]$[moredata]%[controlblock]%"; 

// define a special struct 
enum Type { ... }; 
struct Info { 
    size_t start, end; 
    Type type; 
    // define appropriate ctors 
}; 

// parse the string and return Info obejcts 
std::vector<Info> parse(const std::string& str) { 
     std::vector<Info> v; 
     // loop through the string looking for delims 
     for (size_t b = 0, e = str.size(); b < e; ++b) { 
      // on hitting one such delim create an Info 
      switch(str[ b ]) { 
       case '%': 
        ... 
       case '$;:  
       // initializing the start and then move until 
       // you get the appropriate end delim 
      } 
      // use push_back/emplace_back to insert this newly 
      // created Info object back in the vector 
      v.push_back(Info(start, end, kind)); 
     } 
     return v; 
} 
+0

-1: "मेरा मानना ​​है कि आप संरचना आवंटन के लिए स्ट्रिंग की एक प्रति के बाद संरचना आवंटन के बारे में चिंता कर रहे हैं?" वह 'std :: string' के भीतर आवंटन * के बारे में बात कर रहा है। –

+0

@ निकोलबोलस: मैं अभी भी स्ट्रिंग के भीतर कहां नहीं कहता हूं। मैं काफी निश्चित हूं कि ऐसा कोई मामला नहीं है क्योंकि स्ट्रिंग्स निश्चित-चौड़ाई हैं, जब तक कि आपको और स्ट्रिंग * के भीतर * की अलग समझ न हो। – dirkgently

+0

वह दो मेमोरी आवंटन के बारे में बात कर रहा है। जाहिर है यह उस प्रकार के निर्माण का जिक्र कर रहा है जिसमें 'std :: string', और 'std :: string' की स्ट्रिंग सामग्री शामिल है। –

1

अगर मैं तुम्हें सही ढंग से समझ, आप की रूपरेखा आप निर्धारित किया है कि सच है कि आप आवंटित करने के लिए है कि एक string और अपने डेटा संरचना में एक और डेटा सदस्य आप आवेदन करने के लिए एक अस्वीकार्य लागत लगाता है के माध्यम से है कि कह रहे हैं।

यदि वास्तव में यह मामला है तो मैं कुछ समाधानों के बारे में सोच सकता हूं।

  1. आप अपने कार्यक्रम शुरू होने से पहले इन सभी संरचनाओं को आगे आवंटित कर सकते हैं। उन्हें किसी प्रकार के निश्चित संग्रह में रखें ताकि वे प्रति-निर्मित नहीं हो सकें, और reserve अपने डेटा को पकड़ने के लिए अपने string एस में पर्याप्त बफर।
  2. विवादास्पद जैसा लगता है, आप पुराने सी-शैली char सरणी का उपयोग कर सकते हैं। ऐसा लगता है कि आप पहले स्थान पर string एस का उपयोग करने के अधिकांश कारणों को फोग कर रहे हैं, जो स्मृति प्रबंधन है। हालांकि, आपके मामले में, जब आप स्टार्ट अप पर आवश्यक बफर आकार जानते हैं, तो आप इसे स्वयं संभाल सकते हैं। यदि आपको अन्य सुविधाएं पसंद हैं जो string प्रदान करती हैं, तो ध्यान रखें कि उनमें से अधिकतर अभी भी <algorithm> एस में उपलब्ध है।
1

Variable Sized Struct C++ पर एक नज़र डालें - संक्षिप्त उत्तर यह है कि वेनिला सी ++ में ऐसा करने का कोई तरीका नहीं है।

क्या आपको वास्तव में ढेर पर कंटेनर structs आवंटित करने की आवश्यकता है? स्टैक पर रखने के लिए यह अधिक कुशल हो सकता है, इसलिए उन्हें आवंटित करने की आवश्यकता नहीं है।

1

मुझे यकीन नहीं है कि यह वास्तव में आपकी समस्या का समाधान कर रहा है या नहीं। प्री-आवंटित बफर का उपयोग करके और फिर 'प्लेसमेंट न्यू' ऑपरेटर का उपयोग करके सी ++ में मेमोरी आवंटन को अनुकूलित करने का एक तरीका। मैंने आपकी समस्या को हल करने की कोशिश की क्योंकि मुझे समझ में आया।

unsigned char *myPool = new unsigned char[10000]; 
struct myStruct 
{ 
    myStruct(char* aSource1, char* aSource2) 
    { 
     original = new (myPool) string(aSource1); //placement new 
     data = new (myPool) string(aSource2); //placement new 
    } 
    ~myStruct() 
    { 
     original = NULL; //no deallocation needed 
     data = NULL; //no deallocation needed 
    } 
    string* original; 
    string* data; 
}; 

int main() 
{ 
    myStruct* aStruct = new (myPool) myStruct("h1", "h2"); 

    // Use the struct 

    aStruct = NULL; // No need to deallocate 
    delete [] myPool; 

    return 0; 
} 

[संपादित करें] निकोलबोलस की टिप्पणी के बाद, समस्या थोड़ा और स्पष्ट है। मैंने एक और जवाब लिखने का फैसला किया, वास्तव में यह एक कच्चे चरित्र सरणी का उपयोग करने से बहुत फायदेमंद नहीं है। लेकिन, मुझे अभी भी विश्वास है कि यह बताई गई बाधाओं के भीतर अच्छी तरह से है। आइडिया इस SO question में निर्दिष्ट स्ट्रिंग क्लास के लिए एक कस्टम आवंटक प्रदान करना होगा। आवंटित विधि के क्रियान्वयन में, जैसा कि

pointer allocate(size_type n, void * = 0) 
{ 
    // fail if we try to allocate too much 
    if((n * sizeof(T))> max_size()) { throw std::bad_alloc(); } 

    //T* t = static_cast<T *>(::operator new(n * sizeof(T))); 
    T* t = new (/* provide the address of the original character buffer*/) T[n]; 
    return t; 
} 

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

+0

यह मदद करने के लिए नहीं जा रहा है। यह केवल यह तय करता है कि 'स्ट्रिंग' आवंटित किया गया है, न कि 'string' की * सामग्री *। –

+0

प्रश्न "क्या एक आवंटन में संरचना में निहित संरचना और std :: स्ट्रिंग के लिए स्मृति आवंटित करने का कोई तरीका है?"। और सवाल का कारण यह है कि "इन डेटा प्रकारों में से प्रत्येक के लिए आवश्यक आवंटन की संख्या दोगुना करना एक अस्वीकार्य लागत है।" मुझे लगता है कि स्मृति आवंटन के कारण प्रदर्शन खराब है। यहां, आवंटन से बचा जाता है (स्ट्रिंग और संरचना दोनों के लिए)। (मैं मानता हूं कि यदि स्ट्रिंग मैनिपुलेशन प्रदर्शन को कम कर रहा है, तो यह पर्याप्त नहीं है। लेकिन, यह प्रश्न से स्पष्ट नहीं है) – PermanentGuest

+2

नहीं, यह नहीं है। 'std :: string' स्मृति * आंतरिक * आवंटित करता है। ** वह ** दूसरा स्मृति आवंटन है जिसे वह खत्म करना चाहता है। –

1

सी-स्टाइल स्ट्रिंग को हमेशा आवश्यकतानुसार std::string में परिवर्तित किया जा सकता है। वास्तव में, एक अच्छा मौका है कि प्रोफाइलिंग से आपके अवलोकन केवल आवंटन की संख्या के बजाय आपके डेटा के विखंडन के कारण हैं, और मांग पर std::string बनाना कुशल होगा। बेशक, अपने वास्तविक आवेदन को नहीं जानते यह सिर्फ एक अनुमान है, और वास्तव में इसे तब तक नहीं पता जब तक कि इसका परीक्षण नहीं किया जाता है। मैं एक वर्ग की कल्पना

class my_class { 
    std::string data() const { return self._data; } 
    const char* data_as_c_str() const // In case you really need it! 
    { return self._data; } 
private: 
    int _type; 
    char _data[1]; 
}; 

नोट मैं डेटा लेआउट के लिए एक मानक चालाक सी चाल का इस्तेमाल किया: _data जब तक आप यह होना चाहता हूँ है, इतने लंबे समय के अपने कारखाने समारोह इसके लिए अतिरिक्त स्थान आवंटित करता है के रूप में।

struct my_struct { 
    int type; 
    char data[]; 
}; 

जो आपके C++ कम्पाइलर साथ काम करने का अच्छा बाधाओं हैं: IIRC, C99 भी इसके लिए एक विशेष सिंटेक्स दे दी है। (क्या यह सी ++ 11 मानक में है?)

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


आपके डेटा प्रकारों पर पुनर्विचार करना शायद एक अच्छा विचार है।

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

तरह
class structured_data_reference { 
public: 
    structured_data_reference(const char *data):_data(data) {} 
    std::string get_first_field() const { 
     // Do something interesting with _data to get the first field 
    } 
private: 
    const char *_data; 
}; 

तुम भी अन्य निर्माणकर्ता और असाइनमेंट ऑपरेटर के साथ सही काम करना चाहते हैं (शायद अक्षम असाइनमेंट, और कुछ कदम के लिए उचित लागू करने और कॉपी)। और आप संदर्भित गिनती पॉइंटर्स (उदा। std::shared_ptr) नंगे पॉइंटर्स के बजाय अपने कोड में चाहते हैं।


एक और हैक कि बस std::string उपयोग करने के लिए है, लेकिन पहली प्रविष्टि (या पहले कई) में प्रकार जानकारी स्टोर है संभव है। जब भी आप डेटा तक पहुंचते हैं, तो इसके लिए लेखांकन की आवश्यकता होती है।

+0

संशोधित करना चाहिए "मांग पर एक std :: स्ट्रिंग बनाना कुशल होगा।" कैसे? हर बार जब आप इसे करते हैं, तो आपको स्मृति के दूसरे ब्लॉक की आवश्यकता होती है। –

+0

यह वास्तव में आवेदन पर निर्भर करता है। जैसा कि मैंने उल्लेख किया है, प्रदर्शन में हानि ऐसा नहीं हो सकती क्योंकि 'std :: string' आवंटन करता है, लेकिन क्योंकि यह आपके डेटा को खंडित करता है। दूसरी तरफ, अल्पकालिक 'std :: string' temporaries बनाना, आपके डेटा को खंडित नहीं करेगा, और किसी भी भाग्य के साथ आवंटित करने के लिए त्वरित होगा, और कैश के भीतर आवंटित किया जाएगा। आप 'structured_data_reference :: copy_into_string (std :: string & x)' जैसी विधि का उपयोग करके आवंटन से भी बच सकते हैं जो '_data' में डेटा की एक प्रति के साथ' x' की सामग्री को प्रतिस्थापित करेगा। – Hurkyl

+0

आगे की व्याख्या करने के लिए, आपके संरचना समाधान में 'std :: string' में दो समस्याएं हैं। पहला यह है कि जैसा कि आपने उल्लेख किया है, यह 2 आवंटन (शायद 3) करता है। दूसरा यह है कि आपकी संरचना और स्ट्रिंग की सामग्री स्मृति के बहुत अलग हिस्सों में स्थित हो सकती है। जब उत्तरार्द्ध होता है, हर बार जब आप संरचना का उपयोग करते हैं, तो आपको स्मृति के दो अलग-अलग हिस्सों को छूना पड़ता है। चूंकि संरचना स्वयं छोटा है, इसलिए यह दोनों कैश और टीएलबी अक्षम है यदि स्मृति में संरचना के पास कोई अन्य तत्काल उपयोगी डेटा नहीं है, और कुछ अनुप्रयोगों में, * यह * प्रमुख प्रदर्शन दंड है – Hurkyl

1

वास्तव में दो आवंटन बहुत अधिक प्रतीत हो सकते हैं।

  • एक भी आवंटन
  • एक भी गतिशील आवंटन

यह बहुत अलग नहीं लग सकता है, इसलिए मुझे समझाती हूँ क्या करते हैं: वहाँ हालांकि उनमें कटौती करने के दो तरीके हैं।

1।आप C++

  • struct हैक उपयोग कर सकते हैं हाँ यह सामान्य नहीं है सी ++
  • हाँ यह विशेष देखभाल की आवश्यकता है

तकनीकी तौर पर इसे की आवश्यकता है:

  • प्रतिलिपि निर्माता को अक्षम और असाइनमेंट ऑपरेटर
  • कन्स्ट्रक्टर और विनाशक बनाने private और ऑब्जेक्ट को आवंटित करने और हटाने के लिए कारखाने के तरीके प्रदान करें

ईमानदारी से, यह कठिन तरीका है।

2. आप आवंटन बाहरी struct गतिशील

काफी सरल बच सकते हैं:

struct M { 
    Kind _kind; 
    std::string _data; 
}; 

और फिर ढेर पर M के उदाहरण गुजरती हैं। चालान संचालन की गारंटी देनी चाहिए कि std::string कॉपी नहीं किया गया है (आप इसे सुनिश्चित करने के लिए प्रतिलिपि हमेशा अक्षम कर सकते हैं)।

यह समाधान बहुत सरल है। एकमात्र (मामूली) दोष स्मृति क्षेत्र में है ... लेकिन दूसरी तरफ स्टैक का शीर्ष पहले ही सीपीयू कैश में है।

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