c++ कड़े अलियासिंग नियमों का उल्लंघन किए बिना सी++ में साझा स्मृति बफ़र्स




सी++ प्रोग्राम्स (3)

दरअसल, आपने जो लिखा है वह सख्त अलियासिंग उल्लंघन नहीं है।

सी ++ 11 स्पेक 3.10.10 कहता है:

यदि कोई प्रोग्राम किसी ऑब्जेक्ट के संग्रहीत मूल्य को निम्नलिखित प्रकारों में से किसी एक के अलावा ग्लोबल के माध्यम से एक्सेस करने का प्रयास करता है तो उसका व्यवहार अनिर्धारित है

इसलिए जिस वस्तु को अपरिभाषित व्यवहार का कारण बनता है वह संचयित मूल्य तक पहुंच रहा है, न केवल उस पर एक सूचक बना रहा है आपका उदाहरण कुछ भी उल्लंघन नहीं करता है इसे अगले चरण करने की आवश्यकता होगी: float badValue = smem [0] एसएमएम [0] साझा बफर से संग्रहीत मूल्य प्राप्त करता है, एक अलियासिंग उल्लंघन का निर्माण करता है

बेशक, आप इसे सेट करने से पहले स्मोम [0] को पकड़ने के बारे में नहीं हैं आप इसे पहले लिखने जा रहे हैं। एक ही मेमोरी को सौंपना संग्रहित मूल्य तक नहीं पहुंचता है, इसलिए कोई निष्पक्ष नहीं है, हालांकि, किसी ऑब्जेक्ट के शीर्ष पर लिखने के लिए अवैध है, जबकि यह अभी भी जीवित है। यह साबित करने के लिए कि हम सुरक्षित हैं, हमें 3.8.4 से वस्तु lifespans की आवश्यकता है:

किसी कार्यक्रम को किसी भी ऑब्जेक्ट के जीवन को उस स्टोरेज का पुनः उपयोग करके समाप्त किया जा सकता है जो ऑब्जेक्ट पर कब्जा कर लेता है या किसी नॉन-तुच्छ डिस्ट्रक्टर के साथ एक क्लास प्रकार के ऑब्जेक्ट के लिए डिस्ट्रिक्टर को स्पष्ट रूप से बुला रहा है। गैर-क्षुधाय नाशक के साथ एक वर्ग के प्रकार के उद्देश्य के लिए, प्रोग्राम को स्पष्ट रूप से उस स्टोरेज से पहले डिस्ट्रिक्टर को कॉल करने की आवश्यकता नहीं है, जिस पर ऑब्जेक्ट का पुन: उपयोग किया गया है या जारी किया गया है; ... [डिस्ट्रक्टर्स को फोन नहीं करने के परिणामों के बारे में जारी है]

आपके पास एक पीओडी प्रकार है, इसलिए तुच्छ डिस्ट्रिक्टर, ताकि आप केवल मौखिक रूप से घोषित कर सकें "इंट ऑब्जेक्ट्स अपने जीवन काल के अंत में हैं, मैं फ्लोट्स के लिए जगह का उपयोग कर रहा हूं।" फिर आप फ्लोट्स के लिए जगह का पुन: उपयोग करते हैं, और कोई अलियासिंग उल्लंघन नहीं होता है।

मैं C99 के सख्त अलियासिंग नियमों को तोड़ने के बिना साझा स्मृति बफर को लागू करने के लिए संघर्ष कर रहा हूं।

मान लीजिए मेरे पास कुछ कोड है जो कुछ डेटा को संसाधित करता है और ऑपरेट करने के लिए कुछ 'स्क्रैच' मेमोरी होने की आवश्यकता होती है। मैं इसे जैसा कुछ लिख सकता हूं:

void foo(... some arguments here ...) {
  int* scratchMem = new int[1000];   // Allocate.
  // Do stuff...
  delete[] scratchMem;  // Free.
}

फिर मेरे पास एक और फ़ंक्शन होता है जो कुछ अन्य सामान करता है जिसे स्क्रैच बफर की भी आवश्यकता होती है:

void bar(...arguments...) {
  float* scratchMem = new float[1000];   // Allocate.
  // Do other stuff...
  delete[] scratchMem;  // Free.
}

समस्या यह है कि फू () और बार () को ऑपरेशन के दौरान कई बार बुलाया जा सकता है और प्रदर्शन और मेमोरी फ्रेग्मेंटेशन के मामले में पूरे स्थान पर ढेर सारी आवंटन काफी खराब हो सकते हैं। एक स्पष्ट समाधान एक बार, उचित आकार के एक साझा साझा बफर को आवंटित करना होगा और फिर इसे फ्यू () और बार () में एक तर्क के रूप में, BYOB- शैली के रूप में प्रदान करेगा:

void foo(void* scratchMem);
void bar(void* scratchMem);

int main() {
  const int iAmBigEnough = 5000;
  int* scratchMem = new int[iAmBigEnough];

  foo(scratchMem);
  bar(scratchMem);

  delete[] scratchMem;
  return 0;
}

void foo(void* scratchMem) {
  int* smem = (int*)scratchMem;
  // Dereferencing smem will break strict-aliasing rules!
  // ...
}

void bar(void* scratchMem) {
  float* smem = (float*)scratchMem;
  // Dereferencing smem will break strict-aliasing rules!
  // ...
}


मुझे लगता है मेरे पास अब दो प्रश्न हैं:
- मैं साझा साझा खरोंच मेमोरी बफर कैसे लागू कर सकता हूं जो अलियासिंग नियमों का उल्लंघन नहीं करता है?
- हालांकि उपरोक्त कोड सख्त अलियासिंग नियमों का उल्लंघन करता है, हालांकि उपनाम के साथ कोई 'नुकसान' नहीं किया जा रहा है। इसलिए किसी भी समझदार संकलक उत्पन्न (अनुकूलित) कोड है कि अभी भी मुझे परेशानी में हो सकता है?

धन्यवाद


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

इसलिए, आप char की एक बड़ी सरणी आवंटित कर सकते हैं (किसी भी हस्ताक्षर), और एक ऑफसेट का पता लगा सकते हैं जो alignof(maxalign_t) ; अब आप उस पॉइंटर को ऑब्जेक्ट पॉइंटर के रूप में व्याख्या कर सकते हैं एक बार जब आप उपयुक्त ऑब्जेक्ट का निर्माण कर रहे हैं (जैसे प्लेसमेंट-न्यू में सी ++ में)।

आप निश्चित रूप से किसी मौजूदा ऑब्जेक्ट मेमोरी में लिखना नहीं चाहते हैं; वास्तव में, वस्तु का जीवनकाल परिचित है जो स्मृति के साथ होता है जो ऑब्जेक्ट को दर्शाता है।

उदाहरण:

char buf[50000];

int main()
{
    uintptr_t n = reinterpret_cast<uintptr_t>(buf);
    uintptr_t e = reinterpret_cast<uintptr_t>(buf + sizeof buf);

    while (n % alignof(maxalign_t) != 0) { ++n; }

    assert(e > n + sizeof(T));

    T * p = :: new (reinterpret_cast<void*>(n)) T(1, false, 'x');

    // ...

    p->~T();
}

ध्यान दें कि malloc या new char[N] द्वारा प्राप्त मेमोरी को हमेशा अधिकतम संरेखण के लिए गठबंधन किया गया है (लेकिन अधिक नहीं, और आप अधिक-गठित पते का उपयोग करना चाह सकते हैं)


यदि एक संघ का उपयोग इंट और फ्लोट वैरिएबल रखने के लिए किया जाता है, तो आप सख्त अलियासिंग पास कर सकते हैं। इसके बारे में अधिक जानकारी http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html पर दी गई है।

इसके अलावा निम्नलिखित आलेख देखें

http://blog.regehr.org/archives/959

वह यह करने के लिए यूनियनों का उपयोग करने का एक तरीका देता है





type-punning