2008-12-09 11 views
8

मैं कहां से काम करते हैं, लोगों को ज्यादातर लगता है कि वस्तुओं सबसे अच्छा सी ++ का उपयोग कर initialised कर रहे हैं - शैली निर्माण (कोष्ठकों के साथ), जबकि आदिम प्रकार = ऑपरेटर के साथ initialised किया जाना चाहिए:सी ++ में एक आदिम प्रकार को शुरू करने के लिए = का उपयोग क्यों करें?

std::string strFoo("Foo"); 
int nBar = 5; 

कोई भी क्यों व्याख्या करने में सक्षम हो रहा है वे इस तरह चीजों को पसंद करते हैं, यद्यपि। मैं देख सकता हूं कि std::string = "Foo"; अक्षम होगा क्योंकि इसमें एक अतिरिक्त प्रति शामिल होगी, लेकिन = ऑपरेटर को पूरी तरह से हटाकर और हर जगह कोष्ठक का उपयोग करने में क्या गलत है?

क्या यह एक आम सम्मेलन है? इसके पीछे क्या सोच है?

उत्तर

4

जब तक आप साबित नहीं करते हैं कि यह प्रदर्शन के संबंध में महत्वपूर्ण है, तो मैं आपके उदाहरण (std::string foo = "Foo";) में असाइनमेंट ऑपरेटर का उपयोग करके एक अतिरिक्त प्रति के बारे में चिंता नहीं करता। मुझे आश्चर्य होगा कि ऑप्टिमाइज्ड कोड को देखने के बाद यह प्रतिलिपि भी मौजूद है, मुझे विश्वास है कि वास्तव में उपयुक्त पैरामीटरयुक्त कन्स्ट्रक्टर को कॉल करेगा।

आपके प्रश्न के उत्तर में, हाँ, मैं कहूंगा कि यह एक बहुत आम सम्मेलन है। शास्त्रीय रूप से, लोगों ने अंतर्निहित प्रकारों को शुरू करने के लिए असाइनमेंट का उपयोग किया है, और परंपरा को बदलने के लिए एक अनिवार्य कारण नहीं है। पठनीयता और आदत इस सम्मेलन के लिए पूरी तरह से मान्य कारण हैं कि अंतिम कोड पर इसका कितना कम प्रभाव पड़ता है।

+1

से विरासत में मिला है! हां, यह होगा: सी में, = ऑपरेटर एकमात्र तरीका था, इसलिए यह अभी भी पुरानी टाइमर को "सही लगता है"। धन्यवाद। –

0

यह शैली का एक मुद्दा है। यहां तक ​​कि कथन भी है कि "std :: string =" foo "; अक्षम होगा क्योंकि इसमें एक अतिरिक्त प्रति शामिल होगी" सही नहीं है। यह "अतिरिक्त प्रति" संकलक द्वारा हटा दिया जाता है।

17

= ऑपरेटर या कन्स्ट्रक्टर कॉल के साथ चर शुरू करना अर्थात् समान है, यह केवल शैली का सवाल है। मैं = ऑपरेटर पसंद करता हूं, क्योंकि यह अधिक स्वाभाविक रूप से पढ़ता है।

= ऑपरेटर का उपयोग आमतौर पर एक अतिरिक्त प्रति उत्पन्न नहीं करता है - यह केवल सामान्य कन्स्ट्रक्टर को कॉल करता है। नोट, हालांकि, गैर-आदिम प्रकारों के साथ, यह केवल प्रारंभिकताओं के लिए होता है जो घोषणाओं के साथ ही होते हैं। की तुलना करें:

std::string strFooA("Foo"); // Calls std::string(const char*) constructor 
std::string strFoo = "Foo"; // Calls std::string(const char*) constructor 
          // This is a valid (and standard) compiler optimization. 

std::string strFoo; // Calls std::string() default constructor 
strFoo = "Foo";  // Calls std::string::operator = (const char*) 

आप गैर तुच्छ डिफ़ॉल्ट कंस्ट्रक्टर्स है, बाद के निर्माण से थोड़ा अधिक अक्षम हो सकता है।

C++ standard, खंड 8.5, अनुच्छेद 14 राज्यों:

अन्यथा (जैसे कि, शेष कॉपी-प्रारंभ मामलों के लिए), एक अस्थायी बनाई गई है। उपयोगकर्ता द्वारा परिभाषित रूपांतरण अनुक्रम जो स्रोत प्रकार से गंतव्य प्रकार या किसी व्युत्पन्न वर्ग में परिवर्तित हो सकते हैं, गणना की जाती है (13.3.1.4), और सबसे अच्छा अधिभार संकल्प (13.3) के माध्यम से चुना जाता है। उपयोगकर्ता द्वारा परिभाषित रूपांतरण को चुना गया है जिसे प्रारंभिक अभिव्यक्ति को अस्थायी रूप में परिवर्तित करने के लिए कहा जाता है, जिसका प्रकार उपयोगकर्ता द्वारा परिभाषित रूपांतरण फ़ंक्शन के कॉल द्वारा लौटाया गया प्रकार है, गंतव्य प्रकार के सीवी-क्वालीफायर के साथ। यदि रूपांतरण नहीं किया जा सकता है या संदिग्ध है, तो प्रारंभिकता खराब हो गई है। प्रारंभिक ऑब्जेक्ट को तत्काल नियमों के अनुसार अस्थायी से प्रत्यक्ष-प्रारंभिक किया गया है।) कुछ मामलों में, ऑब्जेक्ट को सीधे शुरू करके अस्थायी को खत्म करने के लिए कार्यान्वयन की अनुमति है; 12.2 देखें।

की धारा 12.2 राज्यों भाग:

यहां तक ​​कि जब अस्थायी वस्तु के निर्माण से बचा जाता है, सभी अर्थ प्रतिबंध के रूप में अगर अस्थायी वस्तु बनाया गया था सम्मान किया जाना चाहिए। [उदाहरण: भले ही प्रतिलिपि निर्माता को नहीं कहा जाता है, भले ही पहुंच (11), सभी अर्थपूर्ण प्रतिबंध, संतुष्ट होंगे।]

+1

= का उपयोग कर एक अस्थायी स्ट्रिंग पैदा करेगा, और का उपयोग कर कि प्रति निर्माता के साथ अस्थायी स्ट्रिंग। (यही कारण है कि प्रपत्र प्रतिलिपि प्रारंभ कहा जाता है, और स्ट्रिंग ओ ("foo" है वस्तु प्रारंभ हो जाएगा) है जिसे प्रत्यक्ष-प्रारंभिक कहा जाता है)। दूसरा अंतर यह है कि = "foo" को एक अंतर्निहित ctor की आवश्यकता होती है। –

+0

हालांकि, संकलक को अस्थायी को खत्म करने की अनुमति है जो प्रतिलिपि बनाई गई है और कॉपी कन्स्ट्रक्टर को पास की गई है। इसलिए आप अस्थायी बनने की सूचना नहीं दे सकते हैं। –

+0

'प्रारंभिक प्रारंभ' बनाम 'प्रारंभिक प्रारंभ' बनाम हर्ब सटर का लेख: http://www.gotw.ca/gotw/036.htm –

2

आप शायद कि कोड

std::string strFoo = "Foo"; 

जैसे एक अतिरिक्त प्रतिलिपि कर से बचने और कोष्ठकों के साथ एक के रूप में एक ही कोड (एक एकल तर्क निर्माता की एक कॉल) के लिए संकलित जाएगा मिल जाएगा।

दूसरी तरफ, ऐसे मामले हैं जहां एक कन्स्ट्रक्टर सदस्य प्रारंभिक सूची जैसे ब्रांड्स का उपयोग करना चाहिए।

मुझे लगता है कि स्थानीय चर बनाने के लिए = या कोष्ठक का उपयोग काफी हद तक व्यक्तिगत पसंद का मामला है।

1

अच्छा, कौन जानता है वे सोचते हैं, लेकिन मैं आदिम प्रकारों के लिए भी पसंद करता हूं, मुख्य रूप से क्योंकि वे ऑब्जेक्ट्स नहीं हैं, और क्योंकि यह उन्हें प्रारंभ करने का "सामान्य" तरीका है।

+0

सी ++ में, आदिम प्रकार की वस्तुएं वस्तुएं हैं, वे केवल कक्षा वस्तुओं नहीं हैं। –

+0

क्या? कब से? मैं ओओपी भावना में वस्तुओं के बारे में बात कर रहा हूँ। सी ++ आदिम प्रकार निश्चित रूप से वस्तुओं नहीं हैं। – hasen

+0

हां। संदर्भ, कार्य और शून्य प्रकार को छोड़कर सब कुछ वस्तुएं हैं। –

0

मेरा मानना ​​है कि एक आदत अधिक है, बहुत कम वस्तुओं को = का उपयोग करके प्रारंभ किया जा सकता है, स्ट्रिंग उनमें से एक है। यह आपके द्वारा किए गए कार्यों को करने का भी एक तरीका है "हर जगह कोष्ठक का उपयोग करके (यह भाषा आपको इसका उपयोग करने की अनुमति देती है)"

11

मुझे बस एक और मूर्खतापूर्ण litb पोस्ट की आवश्यकता महसूस हुई।

string str1 = "foo"; 

कॉपी-प्रारंभ कहा जाता है, क्योंकि जो संकलक करता है, अगर यह किसी भी temporaries छिपाना नहीं करता है, यह है:

string str1(string("foo")); 

जाँच है कि रूपांतरण इस्तेमाल किया निर्माता निहित है बगल में। वास्तव में, सभी अंतर्निहित रूपांतरण मानक प्रारंभिकरण के संदर्भ में मानक द्वारा परिभाषित किए जाते हैं। ऐसा कहा जाता है कि टाइप यू से टाइप टी में एक अंतर्निहित रूपांतरण मान्य है, यदि

T t = u; // u of type U 

मान्य है।

constrast में,

string str1("foo"); 

कर रही है वास्तव में क्या लिखा है, और प्रत्यक्ष प्रारंभ कहा जाता है। यह स्पष्ट रचनाकारों के साथ भी काम करता है।

वैसे, आप का उपयोग करके temporaries की eliding निष्क्रिय कर सकते हैं -fno-छिपाना-कंस्ट्रक्टर्स:

-fno-elide-constructors 
    The C++ standard allows an implementation to omit creating a temporary which 
    is only used to initialize another object of the same type. Specifying this 
    option disables that optimization, and forces G++ to call the copy constructor 
    in all cases. 

स्टैंडर्ड कहते हैं वहाँ व्यावहारिक रूप से

T a = u; 

और बीच कोई अंतर नहीं

T a(u); 

यदि टी और आपके प्रकार का आदिम प्रकार हैं। तो आप दोनों रूपों का उपयोग कर सकते हैं। मुझे लगता है कि यह सिर्फ इसकी शैली है जो लोगों को दूसरे के बजाय पहले फॉर्म का उपयोग करती है।


कुछ लोगों को कुछ स्थिति में पहले उपयोग कर सकते हैं, क्योंकि वे घोषणा को स्पष्ट करना चाहते हैं:

T u(v(a)); 

एक चर u की एक परिभाषा है कि की एक अस्थायी का उपयोग कर के रूप में आरंभ नहीं हो जाता किसी को देखने के migh एक प्रकार v जो उसके निर्माता के लिए पैरामीटर प्राप्त करता है जिसे a कहा जाता है। लेकिन वास्तव में, क्या संकलक कि के साथ करता है यह है:

T u(v a); 

यह एक समारोह घोषणा उस प्रकार v का एक तर्क एक पैरामीटर a कहा जाता है के साथ लेता है, और बनाता है। ताकि लोगों को,

T u = v(a); 

कि स्पष्ट करने के लिए क्या करना भले ही वे

T u((v(a))); 

भी कर सकते थे, क्योंकि वहाँ कभी नहीं कर रहे हैं फ़ंक्शन पैरामीटर आसपास कोष्ठकों, संकलक एक के बजाय एक चर परिभाषा के रूप में यह लिखा होगा समारोह घोषणा भी :)

+1

ऐतिहासिक: आदिम प्रकारों के मामले में, टी ए = आप लंबे समय तक एकमात्र अनुमत रूप था। दूसरा फॉर्म टी ए (यू) प्रारंभिक सूचियों में उपयोग किए जाने वाले मानक में पेश किया गया था, और आदिम प्रकारों के बराबर है। –

0

एक तर्क है कि एक के लिए कर सकता है:

std :: स्ट्रिंग foo ("बार");

है कि यह बातें एक ही हैं, भले ही तर्क गणना परिवर्तन, यानी .:

std :: स्ट्रिंग foo रहता है ("बार", 5) है;

'=' चिह्न के साथ काम नहीं करता है।

एक और बात यह है कि कई वस्तुओं के लिए एक '=' अप्राकृतिक महसूस करता है, उदाहरण के लिए यदि आप एक सरणी वर्ग जहां तर्क लंबाई देता है कहना है:

सरणी आगमन = 5;

अच्छा लग रहा है नहीं, क्योंकि हम मूल्य 5 के साथ एक सरणी का निर्माण नहीं है, लेकिन लंबाई 5 के साथ:

सरणी आगमन (5);

अधिक प्राकृतिक लगता है, क्योंकि आप दिए गए पैरामीटर के साथ ऑब्जेक्ट का निर्माण कर रहे हैं, न केवल एक मूल्य कॉपी कर रहे हैं।

+0

'स्पष्ट' कीवर्ड का उपयोग केवल उस उद्देश्य के लिए किया जाता है - यह सुनिश्चित करने के लिए कि "ऐरे arr = 5" संकलित नहीं होता है। यदि आपको ऐरे (int) कन्स्ट्रक्टर स्पष्ट घोषित किया गया है तो आपको "ऐरे एआर (5)" कहना होगा। –

0

लेकिन फिर आपको ऑब्जेक्ट सिंटैक्स का उपयोग करके प्रारंभिक सूची में प्राइमेटिव प्रारंभ करने के लिए और भी भ्रमित करने के लिए।

foo::foo() 
    ,anInt(0) 
    ,aFloat(0.0) 
{ 
} 
संबंधित मुद्दे