2013-05-17 12 views
9

मुझे पता नहीं लगा सकता है कि निम्न कोड में std :: move कुछ भी अच्छा करता है या यह पूरी तरह से गलत है? कक्षा Object दोनों मूव और कॉपी कन्स्ट्रक्टर परिभाषित है।क्या std :: move effeciency के लिए रिटर्न-स्टेटमेंट में उपयोग किया जाना चाहिए?

पहले:

template<typename T> template <typename F> 
const Object<T> Object<T>::operator*(const F& rhs) const 
{ 
    return std::move(Object(*this) *= rhs); // We end in move constructor 
} 

दूसरा:: ले जाएँ के बिना: चाल के साथ

template<typename T> template <typename F> 
const Object<T> Object<T>::operator*(const F& rhs) const 
{ 
    return Object(*this) *= rhs; // We end in copy constructor 
} 

*= ऑपरेटर के रूप में परिभाषित किया गया है:

template<typename T> template<typename F> 
Object<T>& Object<T>::operator*=(const F& rhs) 
{ 
    for(int i = 0; i < dimension ; i++) 
    { 
     _inner[i] *= rhs; 
    } 
    return *this; 
} 

यहाँ सह है डी मैं इसे परीक्षण करने के लिए उपयोग करें:

Object<double> test(4); 
Object<double> test2(test * 4); 
std::cout << test2; // works fine 

परिणाम पहले मामले हम इस कदम निर्माता में अंत में और दूसरा में हम प्रति निर्माता में खत्म हो।

किसी भी मामले में कोड संकलित करता है।

एक दूसरे से अधिक कुशल है क्योंकि मुझे लगता है कि इसे कॉपी करने के बजाय नई ऑब्जेक्ट को स्थानांतरित करना तेज़ है?

अतिरिक्त जानकारी: मैं निम्नलिखित संकलक का उपयोग करें: जी ++ (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3

+7

'const' मान वापस न करें, स्पष्ट रूप से' std :: move' स्थानीय चर/अस्थायी नहीं है, यह रोकता है (एन) आरवीओ। अपने 'ऑपरेटर *' को 'ऑब्जेक्ट tmp (* यह) के रूप में क्यों न लिखें; टीएमपी * = आरएएस; वापसी टीएमपी; '? इस तरह, कंपाइलर्स देखता है कि आप एक स्थानीय चर लौटाते हैं और इसे वापस लौटने पर स्वचालित रूप से इसे एक रावल्यू में बदल देते हैं। – Xeo

+0

यहां एक नज़र डालें: http://stackoverflow.com/questions/4986673/c11-rvalues-and-move-semantics-confusion – Steve

+0

मैंने अभी तक 'कॉन्स्ट' के बिना परीक्षण किया है, यह स्थिति को नहीं बदलेगा, लेकिन मैं समझ सकता हूं उत्तर से मुझे 'std :: move' की आवश्यकता है क्योंकि मैं' lvalue' लौटाता हूं। अगर दूसरी ओर यह 'rvalue' था और मुझे 'std :: move' की आवश्यकता नहीं थी। और आखिरकार अगर मैंने एक अस्थायी चर का उपयोग किया तो यह स्वचालित रूप से बाहर हो जाएगा? – CodeTower

उत्तर

14

अन्य की तुलना में एक अधिक कुशल के बाद से मैं यह है ग्रहण करेंगे है इसे कॉपी करने के बजाय नई ऑब्जेक्ट को स्थानांतरित करने के लिए तेज़ी से?

हां, std::move का उपयोग करके यहां अधिक कुशल होगा, यह मानते हुए कि ऑब्जेक्ट कॉपी करने से सेमेन्टिक्स को अधिक कुशल बना देता है।

आमतौर पर, जब एक अस्थायी या स्थानीय चर लौटाते हैं, तो सैमेटिक्स को स्वचालित रूप से उपयोग किया जाएगा। हालांकि, इस मामले में आप सीधे अस्थायी रूप से वापस नहीं आ रहे हैं, बल्कि lvalue संदर्भ operator*= द्वारा लौटाया गया संदर्भ। चूंकि lvalue स्थानांतरित नहीं किया जाएगा, इसलिए आपको std::move की आवश्यकता है ताकि इसे रावल्यू में बदल दिया जा सके।

हालांकि, आपको const मान वापस नहीं करना चाहिए, क्योंकि यह वापसी मूल्य को किसी अन्य ऑब्जेक्ट को प्रारंभ करने (या स्थानांतरित करने) को स्थानांतरित करने के लिए उपयोग करने से रोकता है। आपका उदाहरण प्रतिलिपि मूल्य की प्रतिलिपि बना देगा, हालांकि उस प्रति को elided किया जा सकता है।

वैकल्पिक रूप से, आप इसे एक स्थानीय चर का उपयोग कर लागू कर सकते हैं:

template<typename T> template <typename F> 
Object<T> Object<T>::operator*(const F& rhs) const 
{ 
    Object lhs(*this); 
    lhs *= rhs; 
    return lhs; 
} 

इतना ही नहीं दिया गया मान ले जाया जा सकता है, लेकिन इस कदम से ही elided जा सकता है।

+0

मुझे संदेह है कि आरवीओ लालू के मामले का ख्याल रखेगा, इसलिए इसे अलग-अलग होना चाहिए (शायद आरवीओ के लिए थोड़ा सा लाभ भी)। लेकिन आपका आखिरी उदाहरण (स्थानीय चर) इसे वैसे भी सुलझाता है। +1 – syam

+1

@syam: मुझे पूरा यकीन है कि elision केवल तभी अनुमति दी जाती है जब (सीधे) एक अस्थायी या स्थानीय स्वचालित चर लौटाता हो। निश्चित रूप से, मेरे संकलक * lvalue * लौटने पर प्रतिलिपि को elide नहीं करता है। –

+0

कृपया * * non-'const' * 'ऑब्जेक्ट ' वापस लौटने की भी सलाह दें, क्योंकि वापस लौटाए गए मूल्य की बजाय प्रतिलिपि एक प्रतिलिपि होगी क्योंकि यह 'ऑटो सी = ए * बी; ' – Xeo

संबंधित मुद्दे