2014-09-24 9 views
11

कुछ हद तक आश्चर्यजनक रूप से (मेरे लिए), निम्नलिखित दो कार्यक्रमों में काफी बेहतर प्रदर्शन होने बाद से एक के साथ, अलग आउटपुट से संकलन (जीसीसी और बजना के साथ परीक्षण):स्वचालित XValue अनुकूलन

#include <vector> 
int main() 
{ 
    std::vector<int> a(2<<20); 
    for(std::size_t i = 0; i != 1000; ++i) { 
     std::vector<int> b(2<<20); 
     a = b; 
    } 
} 

बनाम

#include <vector> 
int main() 
{ 
    std::vector<int> a(2<<20); 
    for(std::size_t i = 0; i != 1000; ++i) { 
     std::vector<int> b(2<<20); 
     a = std::move(b); 
    } 
} 

क्या कोई मुझे बता सकता है कि कंपाइलर स्वचालित रूप से b को अंतिम असाइनमेंट में एक xvalue क्यों नहीं मानता है और स्पष्ट std::move कास्ट के बिना चाल semantics लागू करते हैं?

संपादित: (g++|clang++) -std=c++11 -O3 -o test test.cpp

+0

आप संकलक के पास क्या पैरामीटर पारित कर रहे हैं? – Joe

+1

मेरा पहला अनुमान यह है कि यह एक अप्रत्याशित तरीके से एक प्रतिलिपि में बदलाव को बदलने के कार्यक्रम के अर्थशास्त्र को बदल देगा। – pmr

+0

@pmr: मुझे यही संदेह है, लेकिन मैं वास्तव में समझना चाहता हूं क्यों। नैतिक रूप से, ऐसा लगता है कि मेरे लिए एक xvalue क्या होना चाहिए। – Xoph

उत्तर

6

Compilers can't break the as-if rule

रूप §1.9/1 कहता है:

इस अंतर्राष्ट्रीय मानक में अर्थ विवरण एक पैरामिट्रीकृत nondeterministic सार मशीन परिभाषित करते हैं। यह अंतर्राष्ट्रीय मानक स्थानों को कार्यान्वयन के अनुरूप संरचना पर कोई आवश्यकता नहीं है। विशेष रूप से, उन्हें सार मशीन की संरचना की प्रतिलिपि बनाने या अनुकरण करने की आवश्यकता नहीं है। बल्कि, अनुरूप कार्यान्वयन (केवल) का अनुकरण करने के सार मशीन की नमूदार व्यवहार के रूप में

नीचे की व्याख्या अर्थात एक संकलक कार्यक्रम की नमूदार व्यवहार को बदल नहीं सकते की आवश्यकता है। स्वचालित रूप से (भले ही कोई प्रतिक्रिया न हो) एक असाइनमेंट को एक असाइनमेंट में कनवर्ट करने से इस कथन को तोड़ दिया जाएगा।

कॉपी एलीशन इस व्यवहार को थोड़ा बदल सकता है, लेकिन यह §12.8/31 द्वारा विनियमित है।

यदि आप मूव संस्करण का उपयोग करना चाहते हैं, तो आपको बाद के उदाहरण में स्पष्ट रूप से इसके लिए पूछना होगा।

+1

ठीक है, इसलिए विशेष रूप से प्रोग्रामर के पास विश्वसनीय प्रतिलिपि/चालक ऑपरेटर/सीटीओआर कॉलिंग होना चाहिए। मैंने किसी भी तरह यह माना कि प्रोग्रामर को इन परिचालनों को संगत रूप से संगत बनाने के लिए समझदारी होगी। मुझे लगता है कि दोनों दृष्टिकोणों में उनके पेशेवर और विपक्ष होंगे, लेकिन मैं देख सकता हूं कि मानक इसे अलग क्यों देखता है। – Xoph

+2

इस विशिष्ट कोड में यह as-if नियम तोड़ नहीं देगा क्योंकि कोई आउटपुट नहीं है –

5

साथ संकलित की अगली नमूना पर नजर डालते हैं (कृपया ध्यान न दें operator= से void वापसी प्रकार):

#include <iostream> 

struct helper 
{ 
    void operator=(helper&&){std::cout<<"move"<<std::endl;} 
    void operator=(const helper&){std::cout<<"copy"<<std::endl;} 
}; 

void fun() 
{ 
    helper a; 
    { 
     helper b; 
     a = b; 
    } 
} 

void gun() 
{ 
    helper a; 
    { 
     helper b; 
     a = std::move(b); 
    } 
} 
int main() 
{ 
    fun(); 
    gun(); 
} 

operator= अपने तर्कों के आधार पर अलग व्यवहार है। कंपाइलर को केवल कोड को अनुकूलित करने की अनुमति है यदि यह अवलोकन योग्य व्यवहार को बनाए रखने में सक्षम है।

, fun एक xvalue से b को ध्यान में रखते हुए इसे कॉल यह कार्यक्रम की नमूदार व्यवहार बदल जाएगा के पल में एक xvalue नहीं है और इस वांछित है और न ही मानक द्वारा अनुमति नहीं है।

+0

धन्यवाद, मैं कन्स्ट्रक्टर कॉलिंग में बदलाव से अवगत था। मैंने माना कि प्रोग्रामर को किसी भी तरह से कन्स्ट्रक्टर/ऑपरेटरों को स्थानांतरित करने और रचनाकारों/ऑपरेटरों को "अर्थात् मिलान करने" की प्रतिलिपि बनाने की आवश्यकता थी, और मुझे लगता है कि यह मेरी दोष है! – Xoph

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