2012-05-07 23 views
6

std :: string (VC11 में) के चाल असाइनमेंट ऑपरेटर का उपयोग करने में क्या लगता है?स्थानांतरण: यह क्या लेता है?

मुझे उम्मीद थी कि यह स्वचालित रूप से उपयोग किया जाएगा क्योंकि अब असाइनमेंट के बाद वी की आवश्यकता नहीं है। क्या इस मामले में std :: move आवश्यक है? यदि ऐसा है, तो मैं गैर-सी ++ 11 स्वैप का भी उपयोग कर सकता हूं।

#include <string> 

struct user_t 
{ 
    void set_name(std::string v) 
    { 
     name_ = v; 
     // swap(name_, v); 
     // name_ = std::move(v); 
    } 

    std::string name_; 
}; 

int main() 
{ 
    user_t u; 
    u.set_name("Olaf"); 
    return 0; 
} 
+2

मुझे कहीं भी एक चालक कन्स्ट्रक्टर नहीं दिख रहा है? – Corbin

+0

@ निकोलबोलस: यह इस प्रश्न से दूरस्थ रूप से संबंधित नहीं है। वह अपनी कक्षा के 'std :: string' सदस्य को स्थानांतरित करने के बारे में पूछ रहा है। वह कक्षा को स्थानांतरित करने की कोशिश नहीं कर रहा है। –

+0

@MooingDuck: ओह। खैर, फिर कभी बुरा मत मानो। मैं वास्तव में करीबी वोट के बारे में बहुत कुछ नहीं कर सकता ... –

उत्तर

11

मुझे उम्मीद थी कि यह स्वचालित रूप से उपयोग किया जाएगा क्योंकि अब असाइनमेंट के बाद वी की आवश्यकता नहीं है। क्या इस मामले में std :: move आवश्यक है?

आंदोलन हमेशा स्पष्ट रूप से अंतराल के लिए कहा जाना चाहिए, जब तक कि उन्हें किसी फ़ंक्शन से वापस नहीं किया जा रहा हो।

यह गलती से कुछ चल रहा है। याद रखें: आंदोलन एक विनाशकारी कार्य है; आप नहीं चाहते कि यह बस हो।

इसके अलावा, यह अजीब होगा अगर name_ = v; के अर्थशास्त्र इस पर आधारित है कि यह फ़ंक्शन में आखिरी पंक्ति है या नहीं।

name_ = v; 
v[0] = 5; //Assuming v has at least one character. 

क्यों पहली पंक्ति कभी कभी एक प्रति पर अमल करना चाहिए और एक चाल दूसरी बार: सब के बाद, यह पूरी तरह से कानूनी कोड है?

यदि हां, तो मैं भी गैर सी ++ 11 स्वैप का उपयोग हो सकता है।

आप जितना चाहें कर सकते हैं, लेकिन std::move इरादे के रूप में अधिक स्पष्ट है। हम जानते हैं कि इसका क्या अर्थ है और आप इसके साथ क्या कर रहे हैं।

+0

मूव मूल रूप से प्रतिलिपि का अनुकूलन है। इसलिए, यह अच्छा होगा अगर संकलक स्वचालित रूप से इस अनुकूलन को निष्पादित करता है अगर ऐसा लगता है कि ऐसा करने के लिए यह सुरक्षित है। – XTF

+0

@XTF: इससे यह पता चल जाएगा कि कौन सा कोड करने जा रहा है, चाहे वह एक प्रतिलिपि या कन्स्ट्रक्टर को स्थानांतरित करे। Elision पहले से ही कुछ समान करता है, लेकिन यह केवल बहुत विशिष्ट परिस्थितियों में होता है। और फिर भी, जब elision नहीं होता है, तब भी आप जानते हैं कि कौन सा कन्स्ट्रक्टर कहलाता है। –

+0

जिस नियम को आपको ध्यान में रखने की आवश्यकता है वह यह है कि नाम के साथ कुछ भी एक लालसा है और निहित आंदोलन केवल रावलों के लिए किया जा सकता है। –

5

अपने उदाहरण में, set_name मूल्य द्वारा स्ट्रिंग लेता है। set_name के अंदर, हालांकि, v एक लवली है। के इन मामलों को अलग से इलाज करते हैं:

user_t u; 
std::string str("Olaf"); // Creates string by copying a char const*. 
u.set_name(std::move(str)); // Moves string. 

set_name अंदर आप std::string की असाइनमेंट ऑपरेटर, जो एक अनावश्यक प्रतिलिपि पड़ता आह्वान। लेकिन वहाँ भी operator= के rvalue overload, जो अपने मामले में और अधिक समझ में आता है है:

void set_name(std::string v) 
{ 
    name_ = std::move(v); 
} 

इस तरह, केवल नकल है कि जगह लेता है स्ट्रिंग constrution (std::string("Olaf")) है।

+0

यहां मूल्य द्वारा पारित तर्क को स्थानांतरित करना कोई समझ नहीं आता है। आप एक प्रतिलिपि से परहेज कर रहे हैं, लेकिन आप पहले से ही प्रारंभिक स्ट्रिंग को मूल्य द्वारा पारित तर्क में कॉपी कर चुके हैं। – mfontanini

+1

@ फोंटानिनी: यह एक आम विकल्प है क्योंकि यह एक समारोह में दोनों रावल्यू और लैवल्यू दोनों से गुजरने के लिए काफी प्रदर्शन करता है। –

+3

@ म्यूइंग डक के उत्तर का विस्तार करने के लिए: केवल मूल्य अर्थशास्त्र का उपयोग करके, यह तय करने के लिए * कॉलर * पर निर्भर करता है कि कोई चाल या प्रतिलिपि बनाना है या नहीं। – mavam

7

स्वीकृत उत्तर एक अच्छा जवाब है (और मैंने इसे ऊपर उठाया है)। लेकिन मैं थोड़ा और विस्तार में इस सवाल को संबोधित करना चाहता था:

मेरे सवाल की मूल है: क्यों यह कदम काम ऑपरेटर स्वचालित रूप से लेने नहीं करता है? संकलक जानता है कि वी असाइनमेंट के बाद उपयोग नहीं किया जाता है, है ना? या C++ 11 को संकलक को होने की आवश्यकता नहीं है जो स्मार्ट है?

इस संभावना चाल अर्थ विज्ञान के डिजाइन के दौरान देखा गया था।एक चरम पर, आप संकलक कुछ स्थिर विश्लेषण करते हैं और वस्तुओं से ले जाने के लिए जब भी संभव करने के लिए चाहते हो सकता है:

void set_name(std::string v) 
{ 
    name_ = v; // move from v if it can be proven that some_event is false? 
    if (some_event) 
     f(v); 
} 

अंततः संकलक से विश्लेषण के इस प्रकार की मांग बहुत मुश्किल है। कुछ कंपाइलर सबूत बनाने में सक्षम हो सकते हैं, और अन्य नहीं हो सकते हैं। इस प्रकार कोड का नेतृत्व करना जो वास्तव में पोर्टेबल नहीं है।

ठीक है, तो बयान के बिना कुछ सरल मामलों के बारे में क्या?

void foo() 
{ 
    X x; 
    Y y(x); 
    X x2 = x; // last use? move? 
} 

खैर, यह अगर y.~Y() देखेंगे x से ले जाया गया है पता करने के लिए मुश्किल है। और सामान्य रूप में:

void foo() 
{ 
    X x; 
    // ... 
    // lots of code here 
    // ... 
    X x2 = x; // last use? move? 
} 

यह संकलक इस विश्लेषण करने के लिए के लिए यदि x सही मायने में नहीं रह गया है x2 के प्रति निर्माण के बाद प्रयोग किया जाता है पता करने के लिए मुश्किल है।

lvalues ​​केवल परोक्ष मामलों में जहां नकल इलिजन पहले से ही अनुमति है में से ले जाया जा सकता है:

तो मूल "चाल" प्रस्ताव निहित चाल के लिए एक नियम है कि वास्तव में सरल है, और बहुत ही रूढ़िवादी था दे दी है।

उदाहरण के लिए:

#include <cassert> 

struct X 
{ 
    int i_; 
    X() : i_(1) {} 
    ~X() {i_ = 0;} 
}; 

struct Y 
{ 
    X* x_; 
    Y() : x_(0) {} 
    ~Y() {assert(x_ != 0); assert(x_->i_ != 0);} 
}; 

X foo(bool some_test) 
{ 
    Y y; 
    X x; 
    if (some_test) 
    { 
     X x2; 
     return x2; 
    } 
    y.x_ = &x; 
    return x; 
} 

int main() 
{ 
    X x = foo(false); 
} 

यहाँ, सी ++ 98/03 नियमों से, इस कार्यक्रम या जोर नहीं हो सकता है, पर किया जाए या नहीं return x पर इलिजन कॉपी होता है निर्भर करता है। यदि ऐसा होता है, तो प्रोग्राम ठीक चलता है। यदि ऐसा नहीं होता है, तो कार्यक्रम जोर देता है।

और इसलिए यह तर्क दिया गया था: जब आरवीओ की अनुमति है, हम पहले से ही ऐसे क्षेत्र में हैं जहां x के मूल्य के संबंध में कोई गारंटी नहीं है। इसलिए हमें इस छूट का लाभ उठाने और x से स्थानांतरित करने में सक्षम होना चाहिए। जोखिम छोटा दिखता था और लाभ विशाल देखा गया। न केवल इसका मतलब यह होगा कि कई मौजूदा कार्यक्रम एक सरल पुनर्मूल्यांकन के साथ बहुत तेज हो जाएंगे, लेकिन इसका मतलब यह भी था कि अब हम कारखाने के कार्यों से "केवल स्थानांतरित" प्रकार वापस कर सकते हैं। यह जोखिम अनुपात के लिए एक बहुत बड़ा लाभ है।

मानकीकरण की प्रक्रिया के अंत में हमने एक छोटे से लालची हो गया और यह भी कहा कि निहित कदम होता है जब एक से-value पैरामीटर लौट (और प्रकार वापसी प्रकार से मेल खाता है)। लाभ यहां अपेक्षाकृत बड़े लगते हैं, हालांकि कोड टूटने का मौका थोड़ा बड़ा है क्योंकि यह ऐसा कोई मामला नहीं है जहां आरवीओ (या है) कानूनी है। लेकिन मेरे पास इस मामले के लिए कोड तोड़ने का प्रदर्शन नहीं है।

तो अंत में, अपने मूल सवाल का जवाब है कि इस कदम अर्थ विज्ञान के मूल डिजाइन मौजूदा कोड को तोड़ने के संबंध में एक बहुत ही रूढ़िवादी मार्ग ले लिया है। अगर ऐसा नहीं होता, तो निश्चित रूप से इसे कमेटी में गोली मार दी जाएगी। इस प्रक्रिया में देर से, कुछ बदलाव हुए जिससे डिजाइन थोड़ा अधिक आक्रामक हो गया। लेकिन इस समय तक मूल प्रस्ताव बहुमत (लेकिन सर्वसम्मति से) समर्थन के साथ मानक में दृढ़ता से फैल गया था।

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