"प्लेसमेंट नए" के लिए क्या उपयोग हैं?


410

क्या यहां किसी ने कभी C ++ का "प्लेसमेंट नया" उपयोग किया है? यदि हां, तो किस लिए? यह मुझे लगता है कि यह केवल मेमोरी-मैप किए गए हार्डवेयर पर उपयोगी होगा।


14
यह सिर्फ वह जानकारी है जिसकी मुझे तलाश थी, ऑब्जेक्ट बिल्डरों को आबंटित मेमोरी पूल पर कॉल करने के लिए। (इन कीवर्ड की उम्मीद करने से भविष्य में किसी को ढूंढना आसान हो जाएगा)।
सिद्धेश बोब

2
इसका उपयोग संघ के निर्माता के C ++ 11 विकिपीडिया लेख में किया जाता है।
HelloGoodbye

@HelloGoodbye, दिलचस्प! आपके द्वारा लिंक किए गए लेख में, आप केवल करने p = ptके Pointबजाय असाइनमेंट ऑपरेटर का उपयोग क्यों नहीं कर सकते हैं new(&p) Point(pt)? मुझे दोनों के बीच के मतभेदों पर आश्चर्य है। क्या पूर्व कॉल operator=प्वाइंट पर होगा , जबकि बाद की कॉल कंस्ट्रक्टर की कॉपी है Point? लेकिन मैं अभी भी बहुत स्पष्ट नहीं हूं कि एक दूसरे से बेहतर क्यों है।
आंद्रेई-निकुला पेट्रे

@ आंद्रेई-निकुलेपेट्रे मैंने खुद प्लेसमेंट न्यू का उपयोग नहीं किया है, लेकिन मुझे लगता है कि आपको इसका उपयोग करना चाहिए - साथ में कॉपी कंस्ट्रक्टर - यदि आपके पास वर्तमान में उस वर्ग का ऑब्जेक्ट नहीं है, तो आपको कॉपी असाइनमेंट ऑपरेटर का उपयोग करना चाहिए। जब तक वर्ग तुच्छ नहीं है; तब यह कोई फर्क नहीं पड़ता कि आप उनमें से किसका उपयोग करते हैं। यही बात वस्तु के विनाश के लिए जाती है। गैर-तुच्छ वर्गों के लिए इसे ठीक से संभालने में विफलता से अजीब व्यवहार हो सकता है, और कुछ स्थितियों में अपरिभाषित व्यवहार भी हो सकता है।
हैलोगूडीबी

@ आंद्रेई-निकुलेपेट्रे वास्तव में, मुझे विकिपीडिया लेख में उदाहरण बहुत बुरा लगता है, क्योंकि यह सिर्फ यह मानता है कि कोई पूर्व वस्तु मौजूद नहीं है और उन्हें एक निर्माण करने की आवश्यकता है। यह मामला नहीं है अगर U::operator=सिर्फ बुलाया गया है।
हैलोगूडीबाई

जवाबों:


364

प्लेसमेंट नया आपको स्मृति में एक ऑब्जेक्ट का निर्माण करने की अनुमति देता है जो पहले से ही आवंटित है।

जब आप किसी ऑब्जेक्ट के कई इंस्टेंसेस बनाने की आवश्यकता हो, तो आप इसे ऑप्टिमाइज़ेशन के लिए कर सकते हैं, और हर बार जब आपको किसी नए इंस्टेंस की आवश्यकता होती है, तो मेमोरी को पुनः आवंटित नहीं करना अधिक तेज़ होता है। इसके बजाय, स्मृति के एक हिस्से के लिए एक ही आवंटन करने के लिए यह अधिक कुशल हो सकता है जो कई वस्तुओं को पकड़ सकता है, भले ही आप इसे एक बार में सभी का उपयोग नहीं करना चाहते।

DevX एक अच्छा उदाहरण देता है :

मानक C ++ प्लेसमेंट नए ऑपरेटर का भी समर्थन करता है, जो पूर्व-आवंटित बफर पर एक ऑब्जेक्ट का निर्माण करता है। मेमोरी पूल का निर्माण करते समय यह उपयोगी होता है, एक कचरा संग्रहकर्ता या बस जब प्रदर्शन और अपवाद सुरक्षा सर्वोपरि होती है (स्मृति के आवंटन के बाद से आवंटन में विफलता का कोई खतरा नहीं है, और पूर्व-आवंटित बफर पर ऑब्जेक्ट का निर्माण करने में कम समय लगता है) :

char *buf  = new char[sizeof(string)]; // pre-allocated buffer
string *p = new (buf) string("hi");    // placement new
string *q = new string("hi");          // ordinary heap allocation

आप यह भी सुनिश्चित करना चाहते हैं कि महत्वपूर्ण कोड (उदाहरण के लिए, पेसमेकर द्वारा निष्पादित कोड में) के एक निश्चित भाग में कोई आवंटन विफलता नहीं हो सकती है। उस स्थिति में आप पहले मेमोरी आवंटित करना चाहते हैं, फिर महत्वपूर्ण अनुभाग में प्लेसमेंट नए का उपयोग करें।

प्लेसमेंट नए में सौदा

आपको मेमोरी बफर का उपयोग करने वाली प्रत्येक वस्तु को नहीं हटाना चाहिए। इसके बजाय आपको केवल मूल बफर को हटाना चाहिए। फिर आपको अपनी कक्षाओं के विध्वंसक को मैन्युअल रूप से कॉल करना होगा। इस पर एक अच्छे सुझाव के लिए, कृपया Stroustrup के अक्सर पूछे जाने वाले प्रश्न देखें: क्या "प्लेसमेंट हटाना" है ?


54
जैसा कि आपको इस सुविधा को कंटेनर ऑब्जेक्ट्स (वेक्टर की तरह) को लागू करने के लिए आवश्यक नहीं है, यह अपग्रेड नहीं किया गया है। यदि आप अपने स्वयं के कंटेनर का निर्माण नहीं कर रहे हैं, तो आपको इस सुविधा का उपयोग करने की आवश्यकता नहीं है।
मार्टिन यॉर्क

26
# किंकर्तव्यविमूढ़ <मेमोरी> को याद रखना भी बहुत महत्वपूर्ण है, अन्यथा आप कुछ प्लेटफार्मों में कुछ भयानक सिरदर्द में भाग सकते हैं जो प्लेसमेंट नए को स्वचालित रूप से नहीं पहचानते हैं
Ramon Zarazua B.

22
सख्ती से, यह delete[]मूल charबफर पर कॉल करने के लिए अपरिभाषित व्यवहार है । प्लेसमेंट newका charउपयोग करके अपने स्टोरेज को पुनः उपयोग करके मूल वस्तुओं के जीवनकाल को समाप्त कर दिया है। यदि आप अब delete[] bufऑब्जेक्ट के डायनामिक प्रकार को कहते हैं, जो आपके स्थिर प्रकार से मेल नहीं खाता है, तो आपके पास अपरिभाषित व्यवहार है। प्लेसमेंट द्वारा उपयोग के लिए प्रचलित कच्ची मेमोरी का उपयोग करना operator new/ उपयोग करना अधिक सुसंगत है । operator deletenew
CB Bailey

31
मैं निश्चित रूप से एक पेसमेकर में ढेर का उपयोग करने पर छोड़ दूंगा :-)
एली बेंडरस्की

15
@RamonZarazua गलत हेडर, यह #include <new>
bit2shift

63

हम इसका उपयोग कस्टम मेमोरी पूल के साथ करते हैं। बस एक स्केच:

class Pool {
public:
    Pool() { /* implementation details irrelevant */ };
    virtual ~Pool() { /* ditto */ };

    virtual void *allocate(size_t);
    virtual void deallocate(void *);

    static Pool::misc_pool() { return misc_pool_p; /* global MiscPool for general use */ }
};

class ClusterPool : public Pool { /* ... */ };
class FastPool : public Pool { /* ... */ };
class MapPool : public Pool { /* ... */ };
class MiscPool : public Pool { /* ... */ };

// elsewhere...

void *pnew_new(size_t size)
{
   return Pool::misc_pool()->allocate(size);
}

void *pnew_new(size_t size, Pool *pool_p)
{
   if (!pool_p) {
      return Pool::misc_pool()->allocate(size);
   }
   else {
      return pool_p->allocate(size);
   }
}

void pnew_delete(void *p)
{
   Pool *hp = Pool::find_pool(p);
   // note: if p == 0, then Pool::find_pool(p) will return 0.
   if (hp) {
      hp->deallocate(p);
   }
}

// elsewhere...

class Obj {
public:
   // misc ctors, dtors, etc.

   // just a sampling of new/del operators
   void *operator new(size_t s)             { return pnew_new(s); }
   void *operator new(size_t s, Pool *hp)   { return pnew_new(s, hp); }
   void operator delete(void *dp)           { pnew_delete(dp); }
   void operator delete(void *dp, Pool*)    { pnew_delete(dp); }

   void *operator new[](size_t s)           { return pnew_new(s); }
   void *operator new[](size_t s, Pool* hp) { return pnew_new(s, hp); }
   void operator delete[](void *dp)         { pnew_delete(dp); }
   void operator delete[](void *dp, Pool*)  { pnew_delete(dp); }
};

// elsewhere...

ClusterPool *cp = new ClusterPool(arg1, arg2, ...);

Obj *new_obj = new (cp) Obj(arg_a, arg_b, ...);

अब आप एकल मेमोरी क्षेत्र में एक साथ वस्तुओं को क्लस्टर कर सकते हैं, एक आवंटनकर्ता का चयन कर सकते हैं जो बहुत तेज़ है, लेकिन कोई निपटारा नहीं करता है, मेमोरी मैपिंग का उपयोग करें, और किसी भी अन्य अर्थ जिसे आप पूल का चयन करके और किसी ऑब्जेक्ट के प्लेसमेंट के लिए एक तर्क के रूप में पारित करना चाहते हैं। नया ऑपरेटर।


1
हां। हम उस बारे में काफी चतुर हैं, लेकिन यह इस सवाल के लिए विषय है।
डॉन वेकफील्ड

2
@jdkoftinoff क्या आपके पास वास्तविक कोड नमूने का कोई लिंक है? मेरे लिए बहुत दिलचस्प लगता है!
विक्टर

@DonWakefield इस पूल में संरेखण को आप कैसे संभालते हैं? क्या आपको allocate()कहीं तर्क के रूप में संरेखण पारित नहीं करना चाहिए ?
मिखाइल वासिलीव

1
@MikhailVasilyev, वास्तविक कार्यान्वयन में, आप निश्चित रूप से इसे संभाल लेंगे। केवल उदाहरण कोड।
डॉन वेकफील्ड

क्या होगा यदि प्लेसमेंट एक अमान्य पता है, तो 0x0 कहें?
चार्ली

51

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


35

मैंने इसका उपयोग वास्तविक समय की प्रोग्रामिंग में किया है। सिस्टम शुरू होने के बाद हम आम तौर पर कोई डायनेमिक एलोकेशन (या डीललोकेशन) नहीं करना चाहते हैं, क्योंकि इसकी कोई गारंटी नहीं है कि कितना समय लगेगा।

मैं जो कुछ भी कर सकता हूं, वह स्मृति के एक बड़े हिस्से का प्रचार करना है (जो भी वर्ग की आवश्यकता हो सकती है, किसी भी राशि को रखने के लिए पर्याप्त है)। फिर, एक बार जब मैं रनटाइम का पता लगाता हूं कि चीजों का निर्माण कैसे किया जाता है, तो प्लेसमेंट नई का उपयोग उन वस्तुओं के निर्माण के लिए किया जा सकता है जहां मैं उन्हें चाहता हूं। एक स्थिति जिसे मैं जानता हूं कि मैंने इसका उपयोग एक विषम परिपत्र बफर बनाने में मदद करने के लिए किया था ।

यह निश्चित रूप से दिल के बेहोश करने के लिए नहीं है, लेकिन यही कारण है कि वे इसके लिए वाक्यविन्यास बनाते हैं।


हाय टेड, क्या आप कृपया आपके पास समाधान के बारे में अधिक साझा कर सकते हैं। मैं एक पूर्व-आवंटित समाधान पर सोच रहा हूं, लेकिन बहुत प्रगति नहीं हुई है। आपका अग्रिम में ही बहुत धन्यवाद!
वियतनाम

1
खैर, वास्तविक हेट्रोजेन्सियस सर्कुलर बफर कोड वास्तव में सही पाने के लिए मुश्किल हिस्सा था। पैलिशमेंट नई तरह से विकराल रूप से दिखती है, लेकिन तुलनात्मक रूप से यह कोई परेशानी नहीं थी।
TED

26

मैंने इसका उपयोग ऑलोक () के माध्यम से स्टैक पर आवंटित वस्तुओं के निर्माण के लिए किया है।

बेशर्म प्लग: मैंने यहां इसके बारे में ब्लॉग किया है


दिलचस्प लेख, लेकिन मुझे यकीन नहीं है कि मैं इस ओवर का उपयोग करने के लाभ को समझता हूं boost::array। क्या आप उस पर थोड़ा विस्तार कर सकते हैं?
ग्राहम

बढ़ावा :: सरणी को सरणी का आकार एक संकलन-समय स्थिर रखने की आवश्यकता है। यह वह सीमा नहीं है।
फेर्रुकियो

2
@Ferruccio यह बहुत अच्छा है, मैंने नोटिस किया कि आपका मैक्रो थोड़ा असुरक्षित है, हालांकि आकार एक एक्सिप्रेशन हो सकता है। यदि x + 1 उदाहरण के लिए पारित किया जाता है, तो आप इसे आकार (प्रकार) * x + 1 तक विस्तारित करेंगे जो गलत होगा। आपको इसे सुरक्षित बनाने के लिए अपने मैक्रो को ऊपर उठाने की आवश्यकता है।
बेंज

एलोका के साथ उपयोग करना मेरे लिए खतरनाक लगता है यदि अपवाद को फेंक दिया जाए क्योंकि आपको अपने सभी ऑब्जेक्ट्स पर डिस्ट्रक्टर्स को कॉल करना होगा।
कैशबैक

14

हेड गीक: बिंगो! आप इसे पूरी तरह से प्राप्त कर चुके हैं - यही इसके लिए एकदम सही है। कई एम्बेडेड वातावरणों में, बाहरी अवरोध और / या समग्र उपयोग परिदृश्य प्रोग्रामर को इसके प्रारंभ से किसी ऑब्जेक्ट के आवंटन को अलग करने के लिए मजबूर करता है। एक साथ गांठ लगाई, C ++ इसे "इंस्टेंटेशन" कहता है; लेकिन जब भी निर्माणकर्ता की कार्रवाई को गतिशील या स्वचालित आवंटन के बिना स्पष्ट रूप से लागू किया जाना चाहिए, तो प्लेसमेंट नया ऐसा करने का तरीका है। यह एक वैश्विक C ++ ऑब्जेक्ट का पता लगाने का एक सही तरीका है जो एक हार्डवेयर घटक (मेमोरी-मैप्ड I / O) के पते पर पिन किया गया है, या किसी भी स्थिर ऑब्जेक्ट के लिए, जो भी कारण से, एक निश्चित पते पर रहना चाहिए।


12

मैंने इसका उपयोग एक वैरिएंट क्लास बनाने के लिए किया है (यानी एक ऐसा ऑब्जेक्ट जो एकल मान का प्रतिनिधित्व कर सकता है जो विभिन्न प्रकारों की संख्या में से एक हो सकता है)।

यदि वैरिएंट वर्ग द्वारा समर्थित सभी मूल्य-प्रकार POD प्रकार (जैसे int, float, double, bool) हैं तो एक टैग की गई C-style संघ पर्याप्त है, लेकिन यदि आप चाहते हैं कि कुछ मान-प्रकार C ++ ऑब्जेक्ट हों ( जैसे std :: string), C संघ सुविधा नहीं करेगा, क्योंकि गैर-POD डेटाटाइप्स को संघ के भाग के रूप में घोषित नहीं किया जा सकता है।

इसलिए इसके बजाय मैं एक बाइट सरणी आवंटित करता हूं जो काफी बड़ा है (जैसे sizeof (the_largest_data_type_I_support)) और उस क्षेत्र में उचित C ++ ऑब्जेक्ट को इनिशियलाइज़ करने के लिए प्लेसमेंट नए का उपयोग करें जब वेरिएंट उस प्रकार का मान रखने के लिए सेट किया गया हो। (और अलग-अलग गैर-पीओडी डेटा प्रकार से दूर जाने पर प्लेसमेंट पहले से हटा दें)


एर्म, गैर-पीओडी डेटाटाइप्स को एक यूनियन के भीतर घोषित किया जा सकता है, इसलिए जब तक आप एक यूनियन कोटर प्रदान करते हैं - और हे - कि ctor शायदnew अपने गैर-पीओडी उपवर्ग को शुरू करने के लिए प्लेसमेंट का उपयोग करेगा । Ref: stackoverflow.com/a/33289972/2757035 मनमाने ढंग से बड़े बाइट सरणी का उपयोग करके इस पहिया को फिर से बनाना कलाबाजी का एक प्रभावशाली टुकड़ा है, लेकिन पूरी तरह से अनावश्यक लगता है, इसलिए, मैंने क्या याद किया है? :)
अंडरस्कोर_ड

6
आपने C ++ 11 से पहले C ++ के सभी संस्करणों को याद किया, कई मामलों में अभी भी समर्थन करने की आवश्यकता है। :)
जेरेमी फ्रेज़र

10

क्रम-निर्धारण के समय प्लेसमेंट नया भी बहुत उपयोगी है (बढ़ावा के साथ कहे: क्रम-निर्धारण)। सी ++ के 10 वर्षों में यह केवल दूसरा मामला है जिसके लिए मुझे प्लेसमेंट नया चाहिए (तीसरा यदि आप साक्षात्कार शामिल हैं :))।


9

यह तब भी उपयोगी है जब आप वैश्विक या सांख्यिकीय रूप से आवंटित संरचनाओं को फिर से शुरू करना चाहते हैं।

पुराना C तरीका memset()सभी एलिमेंट्स को सेट करने के लिए 0. का उपयोग कर रहा था । आप इसे C ++ में vtables और कस्टम ऑब्जेक्ट कंस्ट्रक्टर के कारण नहीं कर सकते।

इसलिए मैं कभी-कभी निम्नलिखित का उपयोग करता हूं

 static Mystruct m;

 for(...)  {
     // re-initialize the structure. Note the use of placement new
     // and the extra parenthesis after Mystruct to force initialization.
     new (&m) Mystruct();

     // do-some work that modifies m's content.
 }

1
क्या इसे दोबारा शुरू करने से पहले आपको एक समान विनाश करने की आवश्यकता नहीं होगी?
हेड गीक

[वर्तनी के लिए संपादित] आमतौर पर - आप करते हैं। लेकिन कभी-कभी, जब आप जानते हैं कि कक्षा स्मृति या अन्य संसाधनों को आवंटित नहीं करती है (या आपने उन्हें बाह्य रूप से निपटाया है - उदाहरण के लिए जब आप मेमोरी पूल का उपयोग करते हैं), तो आप इस तकनीक का उपयोग कर सकते हैं। यह गारंटी देता है कि वी-टेबल पॉइंटर्स ओवरराइट नहीं किए गए हैं। - nimrodm 16 घंटे पहले
nimrodm

1
सी में भी, सभी बिट्स को 0 पर सेट करने का उपयोग केवल अभिन्न प्रकारों के लिए 0 के प्रतिनिधित्व का उत्पादन करने के लिए किया जाता है, न कि अन्य प्रकारों (शून्य पॉइंटर में एक गैर शून्य प्रतिनिधित्व हो सकता है)।
curiousguy

@ क्यूरियसग्यु - आदिम प्रकारों के लिए आप सही हैं (यह प्रोग्राम को पूर्वानुमानित कर देगा जो कि डिबगिंग के लिए एक फायदा है)। हालांकि, C ++ डेटाटिप्स में उनके कंस्ट्रक्टर को (जगह में) चलाया जाएगा और इसे ठीक से इनिशियलाइज़ किया जाएगा।
नीमरोड

9

यह वास्तव में किसी भी प्रकार की डेटा संरचना को लागू करने के लिए आवश्यक है जो सम्मिलित किए गए तत्वों की संख्या के लिए न्यूनतम मेमोरी की तुलना में अधिक मेमोरी आवंटित करता है (यानी, लिंक किए गए संरचना के अलावा कुछ भी जो एक समय में एक नोड आवंटित करता है)।

टेक कंटेनर की तरह unordered_map, vectorया deque। इन सभी की तुलना में आपके द्वारा अब तक डाले गए तत्वों के लिए हर एक प्रविष्टि के लिए ढेर आवंटन की आवश्यकता से बचने के लिए इन सभी को अधिक मेमोरी आवंटित करना आवश्यक है। vectorसबसे सरल उदाहरण के रूप में उपयोग करते हैं ।

जब तुम करोगे:

vector<Foo> vec;

// Allocate memory for a thousand Foos:
vec.reserve(1000);

... कि वास्तव में एक हजार Foos का निर्माण नहीं करता है। यह बस उनके लिए मेमोरी आवंटित / आरक्षित करता है। यदि vectorयहां प्लेसमेंट नए का उपयोग नहीं किया गया है, तो यह Foosपूरे स्थान पर डिफ़ॉल्ट-निर्माण करने के साथ -साथ उन तत्वों को भी नष्ट करने के लिए होगा, जिन्हें आपने पहले कभी नहीं डाला था।

आवंटन! = निर्माण, मुक्त! = विनाश

आम तौर पर ऊपर की तरह कई डेटा संरचनाओं को लागू करने के लिए बोलना, आप मेमोरी को आवंटित करने और तत्वों को एक अविभाज्य चीज़ के रूप में आवंटित करने का इलाज नहीं कर सकते हैं, और आप इसी तरह स्मृति को नष्ट करने और तत्वों को एक अविभाज्य चीज़ के रूप में नष्ट करने का इलाज नहीं कर सकते हैं।

अनावश्यक रूप से बाएं और दाएं जाने वाले निर्माणकर्ताओं और विध्वंसकों से बचने के लिए इन विचारों के बीच एक अलगाव होना चाहिए, और यही कारण है कि मानक पुस्तकालय विचार को अलग std::allocatorकरता है (जो तत्वों का निर्माण या विनाश नहीं करता है जब यह स्मृति को आवंटित / मुक्त करता है *)। कंटेनर जो इसका उपयोग करते हैं जो मैन्युअल रूप से प्लेसमेंट नए का उपयोग करने वाले तत्वों का निर्माण करते हैं और मैन्युअल रूप से विनाशकों के स्पष्ट चालान का उपयोग करते हुए तत्वों को नष्ट करते हैं।

  • मैं इसके डिजाइन से नफरत करता हूं, std::allocatorलेकिन यह एक अलग विषय है जिसके बारे में मैं बात नहीं करूंगा। :-D

इसलिए वैसे भी, मैं इसका बहुत उपयोग करता हूं क्योंकि मैंने कई सामान्य प्रयोजन के मानक-अनुरूप सी ++ कंटेनर लिखे हैं जो मौजूदा लोगों के संदर्भ में नहीं बनाए जा सकते हैं। उनमें शामिल है एक छोटा वेक्टर कार्यान्वयन जिसे मैंने कुछ दशकों पहले सामान्य मामलों में ढेर आवंटन से बचने के लिए बनाया था, और एक मेमोरी-कुशल ट्राई (एक बार में एक नोड आवंटित नहीं करता है)। दोनों ही मामलों में मैं वास्तव में मौजूदा कंटेनरों का उपयोग करके उन्हें लागू नहीं कर सकता था, और इसलिए मुझे placement newअनावश्यक बाएँ और दाएँ चीजों पर निर्माण करने वालों और विनाशकारी से बचने के लिए उपयोग करना पड़ा ।

स्वाभाविक रूप से यदि आप कभी भी कस्टम आवंटनकर्ताओं के साथ व्यक्तिगत रूप से वस्तुओं को आवंटित करने के लिए काम करते हैं, जैसे एक मुफ्त सूची, तो आप आम तौर पर भी उपयोग करना placement newचाहेंगे, इस तरह (मूल उदाहरण जो अपवाद-सुरक्षा या आरएआई से परेशान नहीं होता है):

Foo* foo = new(free_list.allocate()) Foo(...);
...
foo->~Foo();
free_list.free(foo);

8

यदि आप एक कर्नेल का निर्माण कर रहे हैं तो यह उपयोगी है - आप डिस्क या पेजेट से पढ़े गए कर्नेल कोड को कहां रखते हैं? आपको यह जानना होगा कि कहां कूदना है।

या अन्य में, बहुत ही दुर्लभ परिस्थितियों जैसे कि जब आपके पास आवंटित कमरे का भार होता है और एक दूसरे के पीछे कुछ संरचनाएं रखना चाहते हैं। उन्हें ऑफसेट () ऑपरेटर की आवश्यकता के बिना इस तरह से पैक किया जा सकता है। हालांकि इसके लिए अन्य तरकीबें भी हैं।

मेरा यह भी मानना ​​है कि कुछ एसटीएल कार्यान्वयन प्लेसमेंट के नए उपयोग करते हैं, जैसे एसटी :: वेक्टर। वे इस तरह से 2 ^ n तत्वों के लिए कमरा आवंटित करते हैं और उन्हें हमेशा वास्तविक बनाने की आवश्यकता नहीं होती है।


मेमोरी एलोकेशन को कम करना इसका उपयोग करने का एक प्राथमिक कारण है, साथ ही "ट्रिक्स" जैसे कि डिस्क से दूर की वस्तुओं को लोड करना
लेफ्टिकस

मुझे C ++ में लिखी गई किसी भी गुठली का पता नहीं है; अधिकांश कर्नेल सीधे सी। में लिखे गए हैं
एडम रोसेनफील्ड

8
ऑपरेटिंग सिस्टम जिसके साथ मैंने सीखा है कि ओएस की मूल बातें C ++ में लिखी गई हैं: swb.sourceforge.net
mstrobl

8

मुझे लगता है कि यह किसी भी जवाब से उजागर नहीं किया गया है, लेकिन नए प्लेसमेंट के लिए एक और अच्छा उदाहरण और उपयोग मेमोरी विखंडन (मेमोरी पूल का उपयोग करके) को कम करना है। यह एम्बेडेड और उच्च उपलब्धता प्रणालियों में विशेष रूप से उपयोगी है। इस अंतिम मामले में यह विशेष रूप से महत्वपूर्ण है क्योंकि एक प्रणाली के लिए जिसे 24/365 दिन चलाना पड़ता है, उसका कोई विखंडन होना बहुत महत्वपूर्ण है। इस समस्या का मेमोरी लीकेज से कोई लेना-देना नहीं है।

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

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

मैंने इसे VxWorks RTOS के लिए विशेष रूप से अभ्यास में देखा क्योंकि इसकी डिफ़ॉल्ट मेमोरी आवंटन प्रणाली विखंडन से बहुत ग्रस्त है। इसलिए मानक नई / मालॉक विधि के माध्यम से मेमोरी आवंटित करना मूल रूप से परियोजना में निषिद्ध था। सभी मेमोरी आरक्षण एक समर्पित मेमोरी पूल में जाना चाहिए।


8

इसका उपयोग std::vector<>इसलिए किया जाता है क्योंकि std::vector<>आमतौर पर इसमें जितनी मेमोरी होती है उससे कहीं अधिक मेमोरी आवंटित होती objectsहै vector<>


7

मैंने इसका उपयोग मेमोरी मैप्ड फ़ाइलों के साथ वस्तुओं को संग्रहीत करने के लिए किया है।
विशिष्ट उदाहरण एक छवि डेटाबेस था जिसने बड़ी संख्या में बड़ी छवियों (स्मृति में फिट होने से अधिक) को संसाधित किया।


7

मैंने इसे "डायनामिक टाइप" पॉइंटर (सेक्शन "अंडर द हुड") के लिए एक मामूली प्रदर्शन हैक के रूप में उपयोग किया है :

लेकिन यहाँ मुश्किल चाल है जिसे मैं छोटे प्रकारों के लिए तेजी से प्रदर्शन प्राप्त करने के लिए उपयोग करता था: यदि आयोजित किया जा रहा मूल्य एक शून्य के अंदर फिट हो सकता है *, मैं वास्तव में एक नई वस्तु को आवंटित करने से परेशान नहीं हूं, मैं इसे प्लेसमेंट में नए प्लेसमेंट का उपयोग करने के लिए मजबूर करता हूं ।


यदि आयोजित किया जा रहा मूल्य एक शून्य * के अंदर फिट हो सकता है तो क्या होता है? किसी भी पॉइंटर प्रकार को शून्य करने के लिए असाइन करना हमेशा संभव है *। क्या आप हमें कुछ उदाहरण दिखा सकते हैं?
अनुराग an

@ anurag86: मेरी 64 बिट मशीन पर, void*8 बाइट्स लगते हैं। एक-बाइट void*पर आठ-बाइट को इंगित करना थोड़ा मूर्खतापूर्ण है bool। लेकिन यह पूरी तरह से वास्तव में ओवरले boolपर संभव है void*, बहुत कुछ जैसे union { bool b; void* v }। आपको यह जानने के लिए किसी तरह की आवश्यकता है कि जिस चीज को आप कहते हैं void*वह वास्तव में एक bool(या ए short, या ए float, आदि) है। लेख मैं कैसे करना है का वर्णन करने के लिए जुड़ा हुआ है। और, मूल प्रश्न का उत्तर देने के लिए, प्लेसमेंट newएक bool(या अन्य प्रकार) बनाने के लिए उपयोग की जाने वाली सुविधा है जहां एक void*अपेक्षित है, (कलाकारों का उपयोग बाद में मूल्य प्राप्त करने / संशोधित करने के लिए किया जाता है)।
मैक्स लिबर्ट रॉबर्ट

@ anurag86: यह एक ही बात नहीं है, लेकिन आपको टैग किए गए पॉइंटर्स ( en.wikipedia.org/wiki/Tagged_pointer ) में रुचि हो सकती है ।
मैक्स लिबर्ट रॉबर्ट

6

मैंने इसका उपयोग नेटवर्क से प्राप्त संदेशों वाले मेमोरी पर आधारित ऑब्जेक्ट बनाने के लिए किया है।


5

आमतौर पर, प्लेसमेंट नए का उपयोग 'सामान्य नए' की आवंटन लागत से छुटकारा पाने के लिए किया जाता है।

एक अन्य परिदृश्य जहां मैंने इसका उपयोग किया, वह एक ऐसा स्थान है जहां मैं एक ऑब्जेक्ट के लिए पॉइंटर तक पहुंच चाहता था जो अभी भी निर्माण किया जाना था, प्रति-दस्तावेज़ सिंगलटन को लागू करने के लिए।



4

एक जगह जो मैंने चलाई है, वह उन कंटेनरों में है जो एक सन्निहित बफर को आवंटित करते हैं और फिर इसे आवश्यकतानुसार वस्तुओं से भर देते हैं। जैसा कि उल्लेख किया गया है, std :: वेक्टर ऐसा कर सकता है, और मुझे पता है कि MFC CArray और / या CList के कुछ संस्करणों ने ऐसा किया है (क्योंकि यही वह जगह है जहाँ मैं पहली बार भाग गया था)। बफर ओवर-आवंटन विधि एक बहुत ही उपयोगी अनुकूलन है, और प्लेसमेंट नया उस परिदृश्य में वस्तुओं के निर्माण का एकमात्र तरीका है। इसका उपयोग कभी-कभी आपके प्रत्यक्ष कोड के बाहर आवंटित मेमोरी ब्लॉकों में वस्तुओं के निर्माण के लिए भी किया जाता है।

मैंने इसे एक समान क्षमता में उपयोग किया है, हालांकि यह अक्सर नहीं आता है। यह C ++ टूलबॉक्स के लिए एक उपयोगी उपकरण है, हालांकि।


4

स्क्रिप्ट इंजन स्क्रिप्ट से देशी वस्तुओं को आवंटित करने के लिए मूल इंटरफ़ेस में इसका उपयोग कर सकते हैं। उदाहरण के लिए एंजेलस्क्रिप्ट (www.angelcode.com/angelscript) देखें।


3

पर XLL परियोजना में fp.h फ़ाइल देखें http://xll.codeplex.com यह सरणियों कि उन लोगों के साथ चारों ओर उनके आयाम ले जाने के लिए की तरह है के लिए इस मुद्दे को "संकलक के साथ अनुचित chumminess" को हल करती है।

typedef struct _FP
{
    unsigned short int rows;
    unsigned short int columns;
    double array[1];        /* Actually, array[rows][columns] */
} FP;

2

यहां C ++ इन-प्लेस कंस्ट्रक्टर के लिए हत्यारा उपयोग है: एक कैश लाइन के साथ-साथ 2 सीमाओं की अन्य शक्तियां। यहाँ 5 या उससे कम एकल-चक्र निर्देशों के साथ 2 सीमाओं की किसी भी शक्ति के लिए मेरा अल्ट्रा-फास्ट पॉइंटर एलाइनमेंट एल्गोरिथ्म है :

/* Quickly aligns the given pointer to a power of two boundary IN BYTES.
@return An aligned pointer of typename T.
@brief Algorithm is a 2's compliment trick that works by masking off
the desired number in 2's compliment and adding them to the
pointer.
@param pointer The pointer to align.
@param boundary_byte_count The boundary byte count that must be an even
power of 2.
@warning Function does not check if the boundary is a power of 2! */
template <typename T = char>
inline T* AlignUp(void* pointer, uintptr_t boundary_byte_count) {
  uintptr_t value = reinterpret_cast<uintptr_t>(pointer);
  value += (((~value) + 1) & (boundary_byte_count - 1));
  return reinterpret_cast<T*>(value);
}

struct Foo { Foo () {} };
char buffer[sizeof (Foo) + 64];
Foo* foo = new (AlignUp<Foo> (buffer, 64)) Foo ();

अब ऐसा नहीं है कि बस अपने चेहरे पर मुस्कान (:-)) डालें। I ♥♥♥ C ++ 1x

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.