हमारे पास सवाल है कि क्या Ci++
और ++i
C के बीच कोई अंतर है ?
C ++ का उत्तर क्या है?
हमारे पास सवाल है कि क्या Ci++
और ++i
C के बीच कोई अंतर है ?
C ++ का उत्तर क्या है?
जवाबों:
[कार्यकारी सारांश: ++i
यदि आपके पास उपयोग करने का कोई विशिष्ट कारण नहीं है तो उपयोग करें i++
।]
C ++ के लिए, उत्तर थोड़ा अधिक जटिल है।
यदि i
एक सरल प्रकार (सी ++ वर्ग का उदाहरण नहीं है), तो सी के लिए दिया गया उत्तर ("कोई प्रदर्शन अंतर नहीं है") रखता है, क्योंकि कंपाइलर कोड उत्पन्न कर रहा है।
हालांकि, अगर i
, एक सी ++ वर्ग का एक उदाहरण है तो i++
और ++i
से एक के लिए कॉल कर रहे हैं operator++
काम करता है। यहाँ इन कार्यों की एक मानक जोड़ी है:
Foo& Foo::operator++() // called for ++i
{
this->data += 1;
return *this;
}
Foo Foo::operator++(int ignored_dummy_value) // called for i++
{
Foo tmp(*this); // variable "tmp" cannot be optimized away by the compiler
++(*this);
return tmp;
}
चूंकि कंपाइलर कोड उत्पन्न नहीं कर रहा है, लेकिन सिर्फ एक operator++
फ़ंक्शन को कॉल कर रहा है, tmp
चर और इसके संबंधित कॉपी कंस्ट्रक्टर को दूर करने का कोई तरीका नहीं है । यदि कॉपी कंस्ट्रक्टर महंगा है, तो यह एक महत्वपूर्ण प्रदर्शन प्रभाव डाल सकता है।
हाँ। वहाँ है।
++ ऑपरेटर एक फ़ंक्शन के रूप में परिभाषित या नहीं किया जा सकता है। आदिम प्रकार (int, double, ...) के लिए ऑपरेटर बनाए जाते हैं, इसलिए कंपाइलर शायद आपके कोड को ऑप्टिमाइज़ कर पाएंगे। लेकिन ++ ऑब्जेक्ट को परिभाषित करने वाली एक वस्तु के मामले में चीजें अलग हैं।
ऑपरेटर ++ (int) फ़ंक्शन को एक प्रतिलिपि बनाना होगा। ऐसा इसलिए है क्योंकि पोस्टफ़िक्स ++ से यह उम्मीद की जाती है कि वह जो भी मूल्य रखता है, उसकी तुलना में एक अलग मान लौटाए: उसे एक अस्थायी चर में अपना मूल्य रखना चाहिए, अपना मूल्य बढ़ाना चाहिए और अस्थायी वापस लौटना चाहिए। ऑपरेटर ++ (), उपसर्ग ++ के मामले में, प्रतिलिपि बनाने की कोई आवश्यकता नहीं है: ऑब्जेक्ट खुद को बढ़ा सकता है और फिर बस खुद को वापस कर सकता है।
यहाँ बिंदु का एक चित्रण है:
struct C
{
C& operator++(); // prefix
C operator++(int); // postfix
private:
int i_;
};
C& C::operator++()
{
++i_;
return *this; // self, no copy created
}
C C::operator++(int ignored_dummy_value)
{
C t(*this);
++(*this);
return t; // return a copy
}
हर बार जब आप ऑपरेटर ++ (इंट) कहते हैं, तो आपको एक कॉपी बनानी होगी, और कंपाइलर इसके बारे में कुछ नहीं कर सकता है। जब विकल्प दिया जाता है, तो ऑपरेटर ++ () का उपयोग करें; इस तरह आप एक कॉपी नहीं बचाते हैं। यह कई वेतन वृद्धि (बड़े लूप?) और / या बड़ी वस्तुओं के मामले में महत्वपूर्ण हो सकता है।
C t(*this); ++(*this); return t;
है दूसरी पंक्ति में, आप इस पॉइंटर को सही से बढ़ा रहे हैं, इसलिए t
यदि आप इसे बढ़ा रहे हैं तो कैसे अपडेट किया जाए। पहले से ही कॉपी किए गए इस के मूल्य नहीं थे t
?
The operator++(int) function must create a copy.
नहीं ऐसा नहीं है। से अधिक प्रतियां नहींoperator++()
इस मामले के लिए एक बेंचमार्क है जब वेतन वृद्धि ऑपरेटर विभिन्न अनुवाद इकाइयों में हैं। जी ++ 4.5 के साथ कंपाइलर।
अभी के लिए शैली के मुद्दों पर ध्यान न दें
// a.cc
#include <ctime>
#include <array>
class Something {
public:
Something& operator++();
Something operator++(int);
private:
std::array<int,PACKET_SIZE> data;
};
int main () {
Something s;
for (int i=0; i<1024*1024*30; ++i) ++s; // warm up
std::clock_t a = clock();
for (int i=0; i<1024*1024*30; ++i) ++s;
a = clock() - a;
for (int i=0; i<1024*1024*30; ++i) s++; // warm up
std::clock_t b = clock();
for (int i=0; i<1024*1024*30; ++i) s++;
b = clock() - b;
std::cout << "a=" << (a/double(CLOCKS_PER_SEC))
<< ", b=" << (b/double(CLOCKS_PER_SEC)) << '\n';
return 0;
}
// b.cc
#include <array>
class Something {
public:
Something& operator++();
Something operator++(int);
private:
std::array<int,PACKET_SIZE> data;
};
Something& Something::operator++()
{
for (auto it=data.begin(), end=data.end(); it!=end; ++it)
++*it;
return *this;
}
Something Something::operator++(int)
{
Something ret = *this;
++*this;
return ret;
}
वर्चुअल मशीन पर g ++ 4.5 के साथ परिणाम (समय सेकंड में हैं):
Flags (--std=c++0x) ++i i++
-DPACKET_SIZE=50 -O1 1.70 2.39
-DPACKET_SIZE=50 -O3 0.59 1.00
-DPACKET_SIZE=500 -O1 10.51 13.28
-DPACKET_SIZE=500 -O3 4.28 6.82
आइए अब हम निम्नलिखित फ़ाइल लेते हैं:
// c.cc
#include <array>
class Something {
public:
Something& operator++();
Something operator++(int);
private:
std::array<int,PACKET_SIZE> data;
};
Something& Something::operator++()
{
return *this;
}
Something Something::operator++(int)
{
Something ret = *this;
++*this;
return ret;
}
यह वेतन वृद्धि में कुछ नहीं करता है। यह मामला अनुकरण करता है जब वृद्धि में निरंतर जटिलता होती है।
अब परिणाम बहुत भिन्न होते हैं:
Flags (--std=c++0x) ++i i++
-DPACKET_SIZE=50 -O1 0.05 0.74
-DPACKET_SIZE=50 -O3 0.08 0.97
-DPACKET_SIZE=500 -O1 0.05 2.79
-DPACKET_SIZE=500 -O3 0.08 2.18
-DPACKET_SIZE=5000 -O3 0.07 21.90
यदि आपको पिछले मूल्य की आवश्यकता नहीं है, तो इसे पूर्व-वेतन वृद्धि का उपयोग करने की आदत बनाएं। बिलिन प्रकारों के साथ भी सुसंगत रहें, आपको इसकी आदत हो जाएगी और यदि आप कभी भी कस्टम प्रकार के साथ एक बिलिन प्रकार को प्रतिस्थापित करते हैं, तो आवश्यक प्रदर्शन हानि का जोखिम नहीं उठाते हैं।
i++
कहता है increment i, I am interested in the previous value, though
।++i
increment i, I am interested in the current value
या कहता है increment i, no interest in the previous value
। फिर, आपको इसकी आदत हो जाएगी, भले ही आप अभी नहीं हैं।सभी बुराईयो की जड़ समयपूर्व इष्टतमीकरण है। जैसा कि समयपूर्व निराशा है।
for (it=nearest(ray.origin); it!=end(); ++it) { if (auto i = intersect(ray, *it)) return i; }
त्रैमासिक के लिए एक पुनरावृत्ति है , जैसे कि , वास्तविक पेड़ संरचनाकार (बीएसपी, केडी, क्वाडट्री, ऑक्ट्री ग्रिड, आदि) पर कभी भी ध्यान न दें। इस तरह के एक इटरेटर कुछ राज्य, जैसे बनाए रखने के लिए की आवश्यकता होगी parent node
, child node
, index
और इस तरह सामान। सब सब में, मेरा रुख है, भले ही केवल कुछ उदाहरण मौजूद हैं, ...
यह कहना पूरी तरह से सही नहीं है कि संकलक पोस्टफ़िक्स मामले में अस्थायी परिवर्तनशील प्रतिलिपि को दूर नहीं कर सकता है। वीसी के साथ एक त्वरित परीक्षण से पता चलता है कि यह, कम से कम, कुछ मामलों में ऐसा कर सकता है।
निम्न उदाहरण में, उत्पन्न कोड उपसर्ग और उपसर्ग के लिए समान है, उदाहरण के लिए:
#include <stdio.h>
class Foo
{
public:
Foo() { myData=0; }
Foo(const Foo &rhs) { myData=rhs.myData; }
const Foo& operator++()
{
this->myData++;
return *this;
}
const Foo operator++(int)
{
Foo tmp(*this);
this->myData++;
return tmp;
}
int GetData() { return myData; }
private:
int myData;
};
int main(int argc, char* argv[])
{
Foo testFoo;
int count;
printf("Enter loop count: ");
scanf("%d", &count);
for(int i=0; i<count; i++)
{
testFoo++;
}
printf("Value: %d\n", testFoo.GetData());
}
चाहे आप ++ टेस्टफू या टेस्टफू ++ करते हैं, फिर भी आपको वही परिणामी कोड मिलेगा। वास्तव में, उपयोगकर्ता से गिनती को पढ़े बिना, ऑप्टिमाइज़र ने पूरी चीज़ को स्थिर कर दिया। तो यह:
for(int i=0; i<10; i++)
{
testFoo++;
}
printf("Value: %d\n", testFoo.GetData());
निम्नलिखित में परिणाम:
00401000 push 0Ah
00401002 push offset string "Value: %d\n" (402104h)
00401007 call dword ptr [__imp__printf (4020A0h)]
इसलिए जब यह निश्चित रूप से ऐसा होता है कि पोस्टफ़िक्स संस्करण धीमा हो सकता है, तो यह अच्छी तरह से हो सकता है कि यदि आप इसका उपयोग नहीं कर रहे हैं, तो अस्थायी प्रतिलिपि से छुटकारा पाने के लिए ऑप्टिमाइज़र पर्याप्त होगा।
गूगल सी ++ स्टाइल गाइड का कहना है:
पूर्वनिर्धारण और पूर्वनिर्धारण
पुनरावृत्तियों और वेतन वृद्धि संचालकों के उपसर्ग प्रपत्र (++ i) का उपयोग करें पुनरावृत्तियों और अन्य टेम्पलेट ऑब्जेक्ट्स के साथ।
परिभाषा: जब एक चर बढ़ाया जाता है (++ i या i ++) या decremented (--i या i--) और अभिव्यक्ति के मूल्य का उपयोग नहीं किया जाता है, तो किसी को यह तय करना होगा कि प्रीइंक्रिमेंट (decrement) या postincrement (डिक्रीमेंट) करना है या नहीं।
पेशेवरों: जब रिटर्न वैल्यू को नजरअंदाज किया जाता है, तो "प्री" फॉर्म (++ i) "पोस्ट" फॉर्म (i ++) की तुलना में कभी कम कुशल नहीं होता है, और अक्सर अधिक कुशल होता है। ऐसा इसलिए है क्योंकि पोस्ट-इन्क्रीमेंट (या डिक्रीमेंट) के लिए i की एक प्रति की आवश्यकता होती है, जो कि अभिव्यक्ति का मूल्य है। यदि मैं एक पुनरावृत्त या अन्य गैर-स्केलर प्रकार है, तो नकल करना मैं महंगा हो सकता है। चूंकि दो प्रकार की वेतन वृद्धि समान व्यवहार करती है जब मूल्य की अनदेखी की जाती है, तो हमेशा पूर्व वेतन वृद्धि क्यों नहीं होती है?
विपक्ष: परंपरा विकसित हुई, सी में, पोस्ट-इंक्रीमेंट का उपयोग करते समय जब अभिव्यक्ति मूल्य का उपयोग नहीं किया जाता है, विशेष रूप से छोरों के लिए। कुछ लोग पोस्ट-इन्क्रीमेंट को पढ़ना आसान समझते हैं, क्योंकि "सब्जेक्ट" (i) इंग्लिश की तरह "वर्ब" (++) से पहले है।
निर्णय: साधारण स्केलर (गैर-ऑब्जेक्ट) मूल्यों के लिए एक रूप को पसंद करने का कोई कारण नहीं है और हम या तो अनुमति देते हैं। पुनरावृत्तियों और अन्य टेम्पलेट प्रकारों के लिए, पूर्व वेतन वृद्धि का उपयोग करें।
मैं हाल ही में कोड टॉक पर एंड्रयू कोएनिग द्वारा एक उत्कृष्ट पोस्ट को इंगित करना चाहता हूं।
http://dobbscodetalk.com/index.php?option=com_myblog&show=Efficiency-versus-intent.html&Itemid=29
हमारी कंपनी में भी हम स्थिरता और प्रदर्शन के लिए ++ iter के सम्मेलन का उपयोग करते हैं जहां लागू होता है। लेकिन इरादे बनाम प्रदर्शन के बारे में एंड्रयू ने विस्तार से देखा। ऐसे समय होते हैं जब हम ++ iter के बजाय iter ++ का उपयोग करना चाहते हैं।
इसलिए, पहले अपना इरादा तय करें और यदि प्री या पोस्ट मायने नहीं रखता है तो प्री के साथ जाएं क्योंकि अतिरिक्त ऑब्जेक्ट के निर्माण से बचने और इसे फेंकने से कुछ प्रदर्शन लाभ होगा।
@Ketan
... इरादे बनाम प्रदर्शन के बारे में अधिक विस्तार से देखा। ऐसे समय होते हैं जब हम ++ iter के बजाय iter ++ का उपयोग करना चाहते हैं।
स्पष्ट रूप से पोस्ट और पूर्व-वेतन वृद्धि के अलग-अलग शब्दार्थ हैं और मुझे यकीन है कि हर कोई इससे सहमत है कि जब परिणाम का उपयोग किया जाता है तो आपको उपयुक्त ऑपरेटर का उपयोग करना चाहिए। मुझे लगता है कि सवाल यह है कि रिजल्ट ( for
छोरों की तरह) खारिज होने पर क्या करना चाहिए । इस प्रश्न (IMHO) का उत्तर यह है, क्योंकि प्रदर्शन के विचार सबसे अच्छे रूप से नगण्य हैं, इसलिए आपको वही करना चाहिए जो अधिक स्वाभाविक है। खुद के ++i
लिए अधिक स्वाभाविक है, लेकिन मेरा अनुभव बताता है कि मैं अल्पमत में हूं और अधिकांश केi++
लिए कम धातु के उपरि का उपयोग करूंगा आपके कोड को पढ़ने वाले लोगों के ।
आखिरकार यही कारण है कि भाषा को " ++C
" नहीं कहा जाता है । [*]
[*] ++C
अधिक तार्किक नाम होने के बारे में अनिवार्य चर्चा डालें ।
जब वापसी मूल्य का उपयोग नहीं करते हैं तो संकलक को गारंटी दी जाती है कि वह ++ i के मामले में एक अस्थायी का उपयोग न करें । तेज़ होने की गारंटी नहीं है, लेकिन धीमी नहीं होने की गारंटी है।
जब का उपयोग कर दिया गया मान मैं ++ प्रोसेसर पाइपलाइन में दोनों वेतन वृद्धि और बाईं ओर पुश करने के लिए के बाद से वे एक-दूसरे पर निर्भर नहीं है की अनुमति देता है। ++ मैं पाइप लाइन को रोक सकता हूं क्योंकि प्रोसेसर बाईं तरफ शुरू नहीं कर सकता है जब तक कि पूर्व-वेतन वृद्धि ऑपरेशन के माध्यम से सभी तरह से नहीं हो जाता है। फिर से, एक पाइपलाइन स्टाल की गारंटी नहीं है, क्योंकि प्रोसेसर को छड़ी करने के लिए अन्य उपयोगी चीजें मिल सकती हैं।
मार्क: बस यह बताना चाहता था कि ऑपरेटर ++ के अच्छे उम्मीदवार हैं, और यदि कंपाइलर ऐसा करने के लिए चुनाव करता है, तो ज्यादातर मामलों में निरर्थक कॉपी को समाप्त कर दिया जाएगा। (उदाहरण POD प्रकार, जो पुनरावृत्तियां आमतौर पर होती हैं।)
कहा कि, यह अभी भी बेहतर है कि ज्यादातर मामलों में ++ iter का उपयोग करें। :-)
जब आप ऑपरेटरों को मूल्य-वापसी कार्यों के रूप में सोचते हैं और उन्हें कैसे लागू किया जाता है, तो इसके बीच का अंतर ++i
और i++
अधिक स्पष्ट होगा। यह समझना आसान बनाने के लिए कि क्या हो रहा है, निम्न कोड उदाहरण का उपयोग int
करेंगे जैसे कि यह एक था struct
।
++i
चर बढ़ाता है, फिर परिणाम देता है। यह कई मामलों में कोड की केवल एक पंक्ति की आवश्यकता के साथ जगह में और न्यूनतम सीपीयू समय के साथ किया जा सकता है:
int& int::operator++() {
return *this += 1;
}
लेकिन उसी के बारे में नहीं कहा जा सकता है i++
।
वेतन वृद्धि के बाद, i++
अक्सर वेतन वृद्धि से पहले मूल मूल्य को लौटाने के रूप में देखा जाता है । हालाँकि, कोई फ़ंक्शन केवल परिणाम समाप्त होने पर वापस आ सकता है । परिणामस्वरूप, मूल मान वाले चर की एक प्रति बनाना आवश्यक हो जाता है, चर को बढ़ाता है, फिर मूल मान को पकड़े हुए प्रति वापस लौटाता है:
int int::operator++(int& _Val) {
int _Original = _Val;
_Val += 1;
return _Original;
}
जब प्री-इंक्रीमेंट और पोस्ट-इंक्रीमेंट के बीच कोई कार्यात्मक अंतर नहीं होता है, तो कंपाइलर ऑप्टिमाइज़ेशन ऐसा कर सकता है कि दोनों के बीच कोई परफॉर्मेंस डिफरेंस न हो। हालांकि, यदि एक समग्र डेटा प्रकार जैसे कि struct
या class
इसमें शामिल है, तो कॉपी कंस्ट्रक्टर को पोस्ट-इन्क्रीमेंट पर बुलाया जाएगा, और यदि गहरी प्रतिलिपि की आवश्यकता है, तो यह अनुकूलन करना संभव नहीं होगा। जैसे, प्री-इंक्रीमेंट आम तौर पर तेज होता है और पोस्ट-इंक्रीमेंट की तुलना में कम मेमोरी की आवश्यकता होती है।
@ मर्क: मैंने अपने पिछले उत्तर को हटा दिया क्योंकि यह थोड़ा फ्लिप था, और उस अकेले के लिए डाउनवोट के हकदार थे। मुझे वास्तव में लगता है कि यह इस अर्थ में एक अच्छा सवाल है कि यह पूछता है कि बहुत सारे लोगों के दिमाग में क्या है।
सामान्य उत्तर यह है कि ++ मैं i ++ से तेज है, और इसमें कोई संदेह नहीं है, लेकिन बड़ा सवाल यह है कि "आपको कब ध्यान देना चाहिए?"
यदि पुनरावृत्तियों को बढ़ाने में सीपीयू समय का अंश 10% से कम है, तो आप परवाह नहीं कर सकते हैं।
यदि पुनरावृत्तियों को बढ़ाने में CPU समय का अंश 10% से अधिक है, तो आप देख सकते हैं कि कौन से कथन उस छेड़छाड़ कर रहे हैं। देखें कि क्या आप पुनरावृत्तियों का उपयोग करने के बजाय पूर्णांक बढ़ा सकते हैं। संभावना है कि आप कर सकते हैं, और जबकि यह कुछ मायने में कम वांछनीय हो सकता है, संभावना बहुत अच्छी है आप अनिवार्य रूप से उन पुनरावृत्तियों में खर्च किए गए सभी समय को बचाएंगे।
मैंने एक उदाहरण देखा है जहां 90% से अधिक समय में इट्रेटर-इंक्रीमेंट अच्छी तरह से उपभोग कर रहा था। उस मामले में, पूर्णांक-इंक्रीमेंट पर जाने से अनिवार्य रूप से उस राशि से निष्पादन समय कम हो जाता है। (यानी 10x स्पीडअप से बेहतर)
@wilhelmtell
संकलक अस्थायी को खत्म कर सकता है। दूसरे धागे से शब्दभेदी:
C ++ कंपाइलर को स्टैक आधारित टेम्परेरीज़ को खत्म करने की अनुमति दी जाती है, भले ही ऐसा करने से प्रोग्राम का व्यवहार बदल जाए। VCDN के लिए MSDN लिंक:
http://msdn.microsoft.com/en-us/library/ms364057(VS.80).aspx
एक कारण यह है कि आप ++ का उपयोग करना चाहते हैं यहां तक कि अंतर्निहित प्रकारों पर जहां कोई प्रदर्शन लाभ नहीं है, अपने लिए एक अच्छी आदत बनाने के लिए है।
दोनों ही उतने ही तेज़ हैं;) यदि आप चाहते हैं कि यह प्रोसेसर के लिए समान गणना है, तो यह सिर्फ उसी क्रम में होता है जिसमें यह भिन्न होता है।
उदाहरण के लिए, निम्न कोड:
#include <stdio.h>
int main()
{
int a = 0;
a++;
int b = 0;
++b;
return 0;
}
निम्नलिखित विधानसभा का निर्माण करें:
0x0000000100000f24 <main+0>: push %rbp 0x0000000100000f25 <main+1>: mov %rsp,%rbp 0x0000000100000f28 <main+4>: movl $0x0,-0x4(%rbp) 0x0000000100000f2f <main+11>: incl -0x4(%rbp) 0x0000000100000f32 <main+14>: movl $0x0,-0x8(%rbp) 0x0000000100000f39 <main+21>: incl -0x8(%rbp) 0x0000000100000f3c <main+24>: mov $0x0,%eax 0x0000000100000f41 <main+29>: leaveq 0x0000000100000f42 <main+30>: retq
आप देखते हैं कि ++ और b ++ के लिए यह एक इन्क्लोमेनिक है, इसलिए यह एक ही ऑपरेशन है;)
इच्छित प्रश्न तब था जब परिणाम अप्रयुक्त है (सी के लिए प्रश्न से स्पष्ट है)। क्या कोई इसे ठीक कर सकता है क्योंकि सवाल "सामुदायिक विकि" है?
समय से पहले अनुकूलन के बारे में, नुथ अक्सर उद्धृत किया जाता है। ये सही है। लेकिन डोनाल्ड नथ कभी भी उस भयानक कोड का बचाव नहीं करेंगे जो आप इन दिनों में देख सकते हैं। कभी Java Integers (int नहीं) के बीच a = b + c देखा है? यह 3 बॉक्सिंग / अनबॉक्सिंग रूपांतरणों की मात्रा है। ऐसे सामान से बचना जरूरी है। और बेकार में I + + के बजाय i + लिखना एक ही गलती है। संपादित करें: जैसा कि phresnel अच्छी तरह से एक टिप्पणी में रखता है, इसे "समयपूर्व अनुकूलन बुराई के रूप में, समय से पहले निराशाकरण" के रूप में अभिव्यक्त किया जा सकता है।
इस तथ्य पर भी कि लोग I ++ के अधिक अभ्यस्त हैं, एक दुर्भाग्यपूर्ण सी विरासत है, जो K & R द्वारा वैचारिक गलती के कारण होती है (यदि आप आशय तर्क का पालन करते हैं, तो यह एक तार्किक निष्कर्ष है, और K & R का बचाव करना क्योंकि वे K & R व्यर्थ हैं, वे हैं; महान, लेकिन वे भाषा डिजाइनर के रूप में महान नहीं हैं, सी डिजाइन में अनगिनत गलतियां मौजूद हैं, जो () (से) से लेकर strccpy (), एपीआई (इसमें 1 दिन से strlcpy () एपीआई होना चाहिए) तक थी। )।
Btw, मैं उन लोगों में से एक हूं, जिन्होंने C ++ का उपयोग करने के लिए पर्याप्त उपयोग नहीं किया है। फिर भी, मैं इसका उपयोग करता हूं क्योंकि मैं स्वीकार करता हूं कि यह सही है।
++i
अधिक कष्टप्रद नहीं पाया i++
(वास्तव में, मैंने इसे कूलर पाया), लेकिन आपके बाकी पोस्ट को मेरी पूर्ण स्वीकृति प्राप्त है। शायद एक बिंदु जोड़ें "समय से पहले अनुकूलन बुराई है, जैसा कि समयपूर्व निराशा है"
strncpy
उस समय उपयोग किए जा रहे फाइलसिस्टम में एक उद्देश्य को पूरा किया; फ़ाइल नाम 8-वर्ण बफर था और इसे शून्य-समाप्त नहीं किया जाना था। आप भाषा के विकास के भविष्य में 40 साल तक नहीं देखने के लिए उन्हें दोष नहीं दे सकते।
strlcpy()
इस तथ्य से उचित थी कि अभी तक इसका आविष्कार नहीं किया गया था।
ज्ञान के रत्नों के साथ लोगों को प्रदान करने का समय;) - सी ++ पोस्टफिक्स इन्क्रीमेंट बनाने के लिए सरल ट्रिक है, जो प्रीफ़िक्स इन्क्रीमेंट के समान ही व्यवहार करता है (इसे खुद के लिए आविष्कार किया है, लेकिन इसे अन्य लोगों के कोड में भी देखा है, इसलिए ऐसा नहीं है) अकेला)।
मूल रूप से, चाल वापसी के बाद वेतन वृद्धि को स्थगित करने के लिए सहायक वर्ग का उपयोग करना है, और आरएआईआई बचाव के लिए आता है
#include <iostream>
class Data {
private: class DataIncrementer {
private: Data& _dref;
public: DataIncrementer(Data& d) : _dref(d) {}
public: ~DataIncrementer() {
++_dref;
}
};
private: int _data;
public: Data() : _data{0} {}
public: Data(int d) : _data{d} {}
public: Data(const Data& d) : _data{ d._data } {}
public: Data& operator=(const Data& d) {
_data = d._data;
return *this;
}
public: ~Data() {}
public: Data& operator++() { // prefix
++_data;
return *this;
}
public: Data operator++(int) { // postfix
DataIncrementer t(*this);
return *this;
}
public: operator int() {
return _data;
}
};
int
main() {
Data d(1);
std::cout << d << '\n';
std::cout << ++d << '\n';
std::cout << d++ << '\n';
std::cout << d << '\n';
return 0;
}
इन्वेंटेड कुछ भारी कस्टम पुनरावृत्तियों कोड के लिए है, और यह रन-टाइम में कटौती करता है। उपसर्ग बनाम पोस्टफिक्स की लागत अब एक संदर्भ है, और यदि यह कस्टम ऑपरेटर भारी घूम रहा है, तो उपसर्ग और पोस्टफिक्स मेरे लिए एक ही रन-टाइम पैदा करते हैं।
++i
से अधिक तेज़ है i++
क्योंकि यह मान की पुरानी प्रतिलिपि नहीं लौटाता है।
यह भी अधिक सहज है:
x = i++; // x contains the old value of i
y = ++i; // y contains the new value of i
यह C उदाहरण "12" के बजाय "02" को प्रिंट करता है जिसकी आप अपेक्षा कर सकते हैं:
#include <stdio.h>
int main(){
int a = 0;
printf("%d", a++);
printf("%d", ++a);
return 0;
}
#include <iostream>
using namespace std;
int main(){
int a = 0;
cout << a++;
cout << ++a;
return 0;
}