मैं 5 सामान्य श्रेणियों से अवगत हूं, जहां C ++ 03 कंपाइलर को C ++ 11 के रूप में फिर से जमा करना अनियोजित प्रदर्शन बढ़ सकता है जो व्यावहारिक रूप से कार्यान्वयन की गुणवत्ता से असंबंधित हैं। ये सभी कदम शब्दार्थ के रूपांतर हैं।
std::vector
पुनः निर्दिष्ट करें
struct bar{
std::vector<int> data;
};
std::vector<bar> foo(1);
foo.back().data.push_back(3);
foo.reserve(10); // two allocations and a delete occur in C++03
हर बार जब foo
बफर को C ++ 03 में दोबारा लाया जाता है तो वह हर vector
में कॉपी हो जाता है bar
।
C ++ 11 में यह bar::data
एस को स्थानांतरित करता है , जो मूल रूप से स्वतंत्र है।
इस मामले में, यह std
कंटेनर के अंदर अनुकूलन पर निर्भर करता है vector
। नीचे दिए गए प्रत्येक मामले में, std
कंटेनरों का उपयोग सिर्फ इसलिए होता है क्योंकि वे move
C ++ 11 C "11" स्वचालित रूप से आपके कंपाइलर को अपग्रेड करने के लिए कुशल शब्दार्थ हैं। ऑब्जेक्ट जो इसे ब्लॉक नहीं करते हैं जिनमें एक std
कंटेनर होता है, जो स्वचालित रूप से बेहतर move
निर्माण करने वालों को विरासत में मिलता है ।
NRVO की विफलता
जब NRVO (नाम वापसी मूल्य अनुकूलन) विफल रहता है, C ++ 03 में यह कॉपी पर वापस आ जाता है, C ++ 11 पर यह वापस आ जाता है। NRVO की विफलताएं आसान हैं:
std::vector<int> foo(int count){
std::vector<int> v; // oops
if (count<=0) return std::vector<int>();
v.reserve(count);
for(int i=0;i<count;++i)
v.push_back(i);
return v;
}
या और भी:
std::vector<int> foo(bool which) {
std::vector<int> a, b;
// do work, filling a and b, using the other for calculations
if (which)
return a;
else
return b;
}
हमारे पास तीन मान हैं - रिटर्न वैल्यू, और फ़ंक्शन के भीतर दो अलग-अलग मान। एलीशन फ़ंक्शन के भीतर मूल्यों को रिटर्न वैल्यू के साथ 'मर्ज' करने की अनुमति देता है, लेकिन एक दूसरे के साथ नहीं। वे दोनों एक दूसरे के साथ विलय किए बिना रिटर्न वैल्यू में विलय नहीं हो सकते।
मूल मुद्दा यह है कि NRVO चीरा नाजुक है, और return
साइट के पास परिवर्तन नहीं करने वाले कोड में अचानक उस स्थान पर बड़े पैमाने पर प्रदर्शन में कमी हो सकती है, जिसमें कोई निदान नहीं किया गया है। अधिकांश NRVO विफलता मामलों में C ++ 11 एक के साथ समाप्त होता है move
, जबकि C ++ 03 एक प्रतिलिपि के साथ समाप्त होता है।
एक फ़ंक्शन तर्क लौटा रहा है
यहां भी चीरा असंभव है:
std::set<int> func(std::set<int> in){
return in;
}
C ++ 11 में यह सस्ता है: C ++ 03 में कॉपी से बचने का कोई तरीका नहीं है। फ़ंक्शंस के लिए तर्क को रिटर्न वैल्यू के साथ जोड़ा नहीं जा सकता है, क्योंकि जीवनकाल और पैरामीटर और रिटर्न वैल्यू का स्थान कॉलिंग कोड द्वारा प्रबंधित किया जाता है।
हालाँकि, C ++ 11 एक से दूसरे में जा सकता है। (कम खिलौना उदाहरण में, कुछ किया जा सकता है set
)।
push_back
या insert
अंत में कंटेनरों में चीरा नहीं होता है: लेकिन C ++ 11 ओवरलोड्स आवेषण ऑपरेटरों को स्थानांतरित करते हैं, जो प्रतियों को बचाता है।
struct whatever {
std::string data;
int count;
whatever( std::string d, int c ):data(d), count(c) {}
};
std::vector<whatever> v;
v.push_back( whatever("some long string goes here", 3) );
C ++ 03 में एक अस्थायी whatever
बनाया जाता है, फिर इसे वेक्टर में कॉपी किया जाता है v
। 2 std::string
बफ़र्स आवंटित किए जाते हैं, प्रत्येक समान डेटा के साथ, और एक को छोड़ दिया जाता है।
C ++ 11 में एक अस्थायी whatever
बनाया जाता है। whatever&&
push_back
अधिभार तो move
है कि वेक्टर में अस्थायी है v
। एक std::string
बफर आवंटित किया गया है, और वेक्टर में स्थानांतरित कर दिया गया है। एक खाली std::string
छोड़ दिया जाता है।
असाइनमेंट
नीचे @ Jarod42 के जवाब से चोरी।
एलिसन असाइनमेंट के साथ नहीं हो सकता है, लेकिन चाल-से कर सकते हैं।
std::set<int> some_function();
std::set<int> some_value;
// code
some_value = some_function();
यहाँ से some_function
एक उम्मीदवार को वापस लाने के लिए है, लेकिन क्योंकि यह सीधे एक वस्तु का निर्माण करने के लिए उपयोग नहीं किया जाता है, यह elided नहीं किया जा सकता है। C ++ 03 में, अस्थायी रूप से कॉपी की जा रही सामग्री में उपरोक्त परिणाम some_value
। C ++ 11 में, इसे ले जाया जाता है some_value
, जो मूल रूप से मुफ़्त है।
उपरोक्त पूर्ण प्रभाव के लिए, आपको एक कंपाइलर की आवश्यकता होती है जो आपके लिए मूवमेंट कंस्ट्रक्टर और असाइनमेंट को संश्लेषित करता है।
MSVC 2013 लागू करने वाले कंस्ट्रक्टरों को std
कंटेनरों में ले जाते हैं , लेकिन आपके प्रकारों पर मूव कंस्ट्रक्टर्स को संश्लेषित नहीं करते हैं।
इसलिए std::vector
s और इसी तरह के प्रकारों को MSVC2013 में इस तरह के सुधार नहीं मिलते हैं, लेकिन MSVC2015 में उन्हें मिलना शुरू हो जाएगा।
क्लैंग और जीसीसी लंबे समय से निहित चाल निर्माणकर्ताओं को लागू करते हैं। यदि आप पास हो -Qoption,cpp,--gen_move_operations
जाते हैं, तो Intel का 2013 कंपाइलर चाल निर्माणकर्ताओं की अंतर्निहित पीढ़ी का समर्थन करेगा (वे MSVC2013 के साथ संगत होने के प्रयास में डिफ़ॉल्ट रूप से ऐसा नहीं करते हैं)।