2013-04-13 12 views
5

क्यों नीचे दिए गए उदाहरण कोड में, ऑब्जेक्ट दो बार कॉपी किया गया है? थ्रेड क्लास के प्रलेखन कन्स्ट्रक्टर के अनुसार थ्रेड-लोकल स्टोरेज के सभी तर्कों की प्रतिलिपि बनाई गई है, इसलिए हमारे पास पहली प्रतिलिपि का कारण है। दूसरे के बारे में क्या? ऊपर सेstd :: धागा ऑब्जेक्ट दो बार कॉपी क्यों किया जाता है?

class A { 
public: 
    A() {cout << "[C]" << endl;} 
    ~A() {cout << "[~D]" << endl;} 
    A(A const& src) {cout << "[COPY]" << endl;} 
    A& operator=(A const& src) {cout << "[=}" << endl; return *this;} 

    void operator()() {cout << "#" << endl;} 
}; 

void foo() 
{ 
    A a; 
    thread t{a}; 
    t.join(); 
} 

आउटपुट:

[C] 
[COPY] 
[COPY] 
[~D] 
# 
[~D] 
[~D] 

संपादित करें: खैर, हाँ, इस कदम निर्माता को जोड़ने के बाद:

A(A && src) {cout << "[MOVE]" << endl;} 

उत्पादन इस तरह है:

[C] 
[COPY] 
[MOVE] 
[~D] 
# 
[~D] 
[~D] 
+2

बस थोड़ा सुधार: तर्कों को ** थ्रेड-लोकल ** स्टोरेज में कॉपी नहीं किया गया है, लेकिन नए थ्रेड के ढेर पर। थ्रेड-लोकल स्टोरेज एक पूरी तरह से अलग जानवर है; एक धागा-स्थानीय चर, अनिवार्य रूप से, प्रति थ्रेड ग्लोबल वेरिएबल, थ्रेड में किसी भी फ़ंक्शन से सुलभ, प्रत्येक थ्रेड में एक अलग प्रति के साथ। –

+0

वास्तव में, दूसरा '[COPY]' 'MOVE]' है, लेकिन आप इसे नहीं देख सकते हैं क्योंकि आपके पास कोई चालक कन्स्ट्रक्टर लागू नहीं है। – soon

+0

उपरोक्त मामले में, दूसरा [COPY] एक प्रति है। केवल तभी जब आप एक चालक कन्स्ट्रक्टर प्रदान करते हैं या इसे डिफ़ॉल्ट रूप से घोषित करते हैं तो आपको डिफ़ॉल्ट मिल जाता है। – Klaus

उत्तर

3

जो कुछ भी आप ले जाना चाहते हैं या प्रतियों से बचने के लिए, कन्स्ट्रक्टर और std::move को स्थानांतरित करना चाहते हैं।

लेकिन यह मेरे लिए स्वचालित रूप से क्यों नहीं होता है?

सी ++ में स्थान रूढ़िवादी है। यह आम तौर पर केवल तभी स्थानांतरित होगा यदि आप स्पष्ट रूप से std::move() लिखते हैं। ऐसा इसलिए किया गया था क्योंकि बहुत स्पष्ट परिस्थितियों से परे विस्तारित, अर्थात् स्थानांतरित करें, पुराने कोड को तोड़ सकता है। स्वचालित कारणों को अक्सर इस कारण से परिस्थितियों के बहुत सावधान सेट तक ही सीमित किया जाता है।

इस स्थिति में प्रतियों से बचने के लिए, आपको का उपयोग करके a को स्थानांतरित करने की आवश्यकता है (भले ही इसे std::thread में पास किया जाए)। कारण यह पहली बार प्रतिलिपि बनाता है क्योंकि std :: thread गारंटी नहीं दे सकता है कि std :: thread (और आपने इसे स्पष्ट रूप से इसमें स्थानांतरित नहीं किया है) बनाने के बाद मान मौजूद होगा। इस प्रकार, यह सुरक्षित चीज़ करेगा और एक प्रतिलिपि बनाएगा (आपने जो भी पारित किया है उसे संग्रहीत करने के लिए संदर्भ/सूचक नहीं लें: कोड को पता नहीं है कि आप इसे जीवित रखेंगे या नहीं)।

दोनों चालक कन्स्ट्रक्टर होने और std::move का उपयोग करने से संकलक को आपकी संरचना को अधिकतम और कुशलतापूर्वक स्थानांतरित करने की अनुमति मिल जाएगी। यदि आप वीसी ++ (सीटीपी के साथ या नहीं) का उपयोग कर रहे हैं, तो आपको स्पष्ट रूप से चालक कन्स्ट्रक्टर लिखना होगा, अन्यथा एमएसवीसी (कभी-कभी गलती से) घोषित करेगा और कॉपी कन्स्ट्रक्टर का उपयोग करेगा।

0

कोशिश के साथ: धागा टी {std :: एम ove (क)};

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