c++ - सी++ में मानक ऑपरेटरों पर मुझे किस मामले में memcpy का उपयोग करना चाहिए?




performance memory (5)

मैं memcpy का उपयोग करके बेहतर प्रदर्शन कब प्राप्त कर सकता हूं या इसका उपयोग करने से मुझे कैसे फायदा हो सकता है? उदाहरण के लिए:

float a[3]; float b[3];

कोड है:

memcpy(a, b, 3*sizeof(float));

इस से तेज ?

a[0] = b[0];
a[1] = b[1];
a[2] = b[2];

Memcpy के लाभ? शायद पठनीयता। अन्यथा, आपको या तो कई असाइनमेंट करना होगा या प्रतिलिपि बनाने के लिए लूप होना होगा, न कि केवल memcpy के रूप में सरल और स्पष्ट हैं (बेशक, जब तक आपके प्रकार सरल होते हैं और निर्माण / विनाश)।

साथ ही, memcpy आमतौर पर विशिष्ट प्लेटफार्मों के लिए अपेक्षाकृत अनुकूलित किया जाता है, इस बिंदु पर कि यह सरल असाइनमेंट की तुलना में इतना धीमा नहीं होगा, और यह भी तेज़ हो सकता है।


आप केवल memcpy उपयोग कर सकते हैं यदि आपके द्वारा कॉपी की जा रही वस्तुओं में कोई स्पष्ट memcpy नहीं है, इसलिए उनके सदस्यों (तथाकथित पीओडी, "सादा पुराना डेटा")। तो float लिए memcpy कॉल करना ठीक है, लेकिन यह गलत है, उदाहरण के लिए, std::string

लेकिन काम का हिस्सा आपके लिए पहले से ही किया जा चुका है: std::copy <algorithm> से std::copy अंतर्निहित प्रकारों के लिए विशिष्ट है (और संभवतः हर दूसरे पीओडी-प्रकार के लिए - एसटीएल कार्यान्वयन पर निर्भर करता है)। इसलिए std::copy(a, a + 3, b) लिखना तेजी से (कंपाइलर अनुकूलन के बाद) memcpy रूप में है, लेकिन कम त्रुटि-प्रवण है।


कंपाइलर्स विशेष रूप से memcpy कॉल अनुकूलित करते हैं, कम से कम clang और gcc करता है। तो आपको इसे कहीं भी पसंद करना चाहिए।


क्षमता आपकी चिंता नहीं होनी चाहिए।
स्वच्छ रखरखाव कोड लिखें।

यह मुझे परेशान करता है कि इतने सारे उत्तरों इंगित करते हैं कि memcpy () अक्षम है। यह स्मृति के ब्लॉक ब्लॉक (सी प्रोग्राम के लिए) का सबसे प्रभावी तरीका बनने के लिए डिज़ाइन किया गया है।

इसलिए मैंने निम्नलिखित परीक्षण के रूप में लिखा:

#include <algorithm>

extern float a[3];
extern float b[3];
extern void base();

int main()
{
    base();

#if defined(M1)
    a[0] = b[0];
    a[1] = b[1];
    a[2] = b[2];
#elif defined(M2)
    memcpy(a, b, 3*sizeof(float));    
#elif defined(M3)
    std::copy(&a[0], &a[3], &b[0]);
 #endif

    base();
}

फिर कोड की तुलना करने के लिए उत्पादन:

g++ -O3 -S xr.cpp -o s0.s
g++ -O3 -S xr.cpp -o s1.s -DM1
g++ -O3 -S xr.cpp -o s2.s -DM2
g++ -O3 -S xr.cpp -o s3.s -DM3

echo "=======" >  D
diff s0.s s1.s >> D
echo "=======" >> D
diff s0.s s2.s >> D
echo "=======" >> D
diff s0.s s3.s >> D

इसके परिणामस्वरूप: (हाथ से जोड़े गए टिप्पणियां)

=======   // Copy by hand
10a11,18
>   movq    [email protected](%rip), %rcx
>   movq    [email protected](%rip), %rdx
>   movl    (%rdx), %eax
>   movl    %eax, (%rcx)
>   movl    4(%rdx), %eax
>   movl    %eax, 4(%rcx)
>   movl    8(%rdx), %eax
>   movl    %eax, 8(%rcx)

=======    // memcpy()
10a11,16
>   movq    [email protected](%rip), %rcx
>   movq    [email protected](%rip), %rdx
>   movq    (%rdx), %rax
>   movq    %rax, (%rcx)
>   movl    8(%rdx), %eax
>   movl    %eax, 8(%rcx)

=======    // std::copy()
10a11,14
>   movq    [email protected](%rip), %rsi
>   movl    $12, %edx
>   movq    [email protected](%rip), %rdi
>   call    _memmove

1000000000 लूप के अंदर उपरोक्त चलाने के लिए समय के परिणाम जोड़े गए।

   g++ -c -O3 -DM1 X.cpp
   g++ -O3 X.o base.o -o m1
   g++ -c -O3 -DM2 X.cpp
   g++ -O3 X.o base.o -o m2
   g++ -c -O3 -DM3 X.cpp
   g++ -O3 X.o base.o -o m3
   time ./m1

   real 0m2.486s
   user 0m2.478s
   sys  0m0.005s
   time ./m2

   real 0m1.859s
   user 0m1.853s
   sys  0m0.004s
   time ./m3

   real 0m1.858s
   user 0m1.851s
   sys  0m0.006s

std::copy() प्रयोग करें। g++ नोट्स के लिए हेडर फ़ाइल के रूप में:

यह इनलाइन फ़ंक्शन जब भी संभव हो @c memmove को कॉल करने के लिए उबाल जाएगा।

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







copying