क्या प्रतिलिपि आरंभीकरण और प्रत्यक्ष आरंभीकरण के बीच अंतर है?


244

मान लीजिए कि मेरा यह कार्य है:

void my_test()
{
    A a1 = A_factory_func();
    A a2(A_factory_func());

    double b1 = 0.5;
    double b2(0.5);

    A c1;
    A c2 = A();
    A c3(A());
}

प्रत्येक समूह में, क्या ये कथन समान हैं? या कुछ आदतों में एक अतिरिक्त (संभवतः अनुकूलन योग्य) प्रति है?

मैंने लोगों को दोनों बातें कहते देखा है। कृपया प्रमाण के रूप में पाठ का हवाला दें । कृपया अन्य मामले भी जोड़ें।


1
और @JohannesSchaub द्वारा चर्चा किया गया चौथा मामला है - A c1; A c2 = c1; A c3(c1);
डैन निसेनबाम जूल

1
बस एक 2018 नोट: नियम C ++ 17 में बदल गए हैं, देखें, उदाहरण के लिए, यहां । यदि मेरी समझ सही है, तो C ++ 17 में, दोनों कथन प्रभावी रूप से समान हैं (भले ही प्रतिलिपि ctor स्पष्ट हो)। इसके अलावा, अगर इनिट एक्सप्रेशन अन्य प्रकार की तुलना में होगा A, तो कॉपी इनिशियलाइज़ेशन को कॉपी / मूव कंडक्टर के अस्तित्व की आवश्यकता नहीं होगी। यही कारण है कि std::atomic<int> a = 1;C ++ 17 में ठीक है, लेकिन पहले नहीं।
डैनियल लैंगर

जवाबों:


246

C ++ 17 अद्यतन

C ++ 17 में, A_factory_func()एक अस्थायी वस्तु (C ++ <= 14) बनाने से बदले जाने का अर्थ यह है कि C ++ 17 में जिस भी वस्तु की अभिव्यक्ति शुरू की गई है (शिथिल रूप से बोलना), उसको प्रारंभ करना। ये ऑब्जेक्ट्स ("परिणाम ऑब्जेक्ट्स") एक घोषणा (जैसे a1) द्वारा बनाए गए वेरिएबल्स हैं , जब आरंभीकरण समाप्त होने पर कृत्रिम ऑब्जेक्ट बनाए जाते हैं, या संदर्भ बंधन के लिए किसी ऑब्जेक्ट की आवश्यकता होती है (जैसे, A_factory_func();अंतिम मामले में) । एक वस्तु कृत्रिम रूप से बनाई जाती है, जिसे "अस्थायी भौतिककरण" कहा जाता है, क्योंकि A_factory_func()इसमें एक चर या संदर्भ नहीं होता है जो अन्यथा मौजूद होने के लिए एक वस्तु की आवश्यकता होती है)।

हमारे मामले में उदाहरण के रूप में, a1और a2विशेष नियमों के मामले में कहा गया है कि इस तरह की घोषणाओं में, एक ही प्रकार के एक प्रचलित इक्वलाइज़र का परिणाम ऑब्जेक्ट a1चर है a1, और इसलिए A_factory_func()सीधे ऑब्जेक्ट को इनिशियलाइज़ करता है a1। किसी भी मध्यस्थ कार्यात्मक-शैली के कलाकारों पर कोई प्रभाव नहीं पड़ेगा, क्योंकि A_factory_func(another-prvalue)सिर्फ "से गुजरता है" बाहरी वस्तु के परिणाम वस्तु के भीतर के परिणाम का परिणाम भी होता है।


A a1 = A_factory_func();
A a2(A_factory_func());

किस प्रकार के A_factory_func()रिटर्न पर निर्भर करता है। मुझे लगता है कि यह एक रिटर्न देता है A- फिर यह वही कर रहा है - सिवाय इसके कि जब कॉपी कंस्ट्रक्टर स्पष्ट हो, तो पहले वाला विफल हो जाएगा। 8.6 / 14 पढ़ें

double b1 = 0.5;
double b2(0.5);

यह वही कर रहा है क्योंकि यह बिल्ट-इन टाइप है (इसका मतलब यहां क्लास टाइप नहीं है)। 8.6 / 14 पढ़ें ।

A c1;
A c2 = A();
A c3(A());

यह वही नहीं कर रहा है। यदि Aकोई गैर-POD है, तो पहला डिफ़ॉल्ट-आरंभ करता है, और POD के लिए कोई प्रारंभ नहीं करता है (पढ़ें 8.6 / 9 )। दूसरी प्रति इनिशियलाइज़ करती है: वैल्यू इनिशियलाइज़ करती है एक अस्थायी और फिर उस वैल्यू को कॉपी करती है c2(पढ़ें 5.2.3 / 2 और 8.6 / 14 )। इस पाठ्यक्रम के लिए एक गैर-स्पष्ट प्रतिलिपि निर्माता की आवश्यकता होगी (पढ़ें 8.6 / 14 और 12.3.1 / 3 और 13.3.1.3/1 )। तीसरा एक फ़ंक्शन के लिए एक फ़ंक्शन घोषणापत्र बनाता है जो एक c3रिटर्न देता है Aऔर जो एक फ़ंक्शन पॉइंटर को एक रिटर्न A( एक 8.2 ) पढ़ता है


इनिशियलाइज़ेशन में डायरेक्ट और कॉपी इनिशियलाइज़ेशन

जबकि वे समान दिखते हैं और ऐसा ही करने वाले होते हैं, ये दोनों रूप कुछ मामलों में उल्लेखनीय रूप से भिन्न होते हैं। आरंभीकरण के दो रूप प्रत्यक्ष और प्रतिलिपि आरंभीकरण हैं:

T t(x);
T t = x;

व्यवहार है हम उनमें से प्रत्येक के लिए विशेषता कर सकते हैं:

  • प्रत्यक्ष आरंभीकरण एक अतिभारित कार्य के लिए एक फ़ंक्शन कॉल की तरह व्यवहार करता है: कार्य, इस मामले में, T(सहित explicit) के निर्माता हैं, और तर्क है x। ओवरलोड रिज़ॉल्यूशन में सबसे अच्छा मिलान करने वाला कंस्ट्रक्टर मिलेगा, और जब आवश्यक होगा कोई आवश्यक रूपांतरण करेगा।
  • प्रतिलिपि आरंभीकरण एक अंतर्निहित रूपांतरण अनुक्रम का निर्माण करता है: यह xएक प्रकार की वस्तु में बदलने की कोशिश करता है T। (यह तब उस ऑब्जेक्ट को इन-इनिशियलाइज्ड ऑब्जेक्ट में कॉपी कर सकता है, इसलिए कॉपी कंस्ट्रक्टर की भी आवश्यकता है - लेकिन यह नीचे दिए गए महत्वपूर्ण नहीं है)

जैसा कि आप देखते हैं, कॉपी इनिशियलाइज़ेशन किसी तरह से संभव अंतर्निहित रूपांतरण के संबंध में प्रत्यक्ष आरंभीकरण का एक हिस्सा है: जबकि प्रत्यक्ष इनिशियलाइज़ेशन में कॉल करने के लिए सभी कंस्ट्रक्टर उपलब्ध हैं, और इसके अलावा किसी भी अंतर्निहित रूपांतरण को तर्क प्रकारों से मेल खाने की आवश्यकता हो सकती है, कॉपी सत्यापन बस एक अंतर्निहित रूपांतरण अनुक्रम सेट कर सकते हैं।

मैंने कड़ी मेहनत की और निर्माणकर्ताओं के माध्यम से "स्पष्ट" का उपयोग किए बिना, उन रूपों में से प्रत्येक के लिए अलग-अलग पाठ को आउटपुट करने के लिए निम्न कोड प्राप्तexplicit किया।

#include <iostream>
struct B;
struct A { 
  operator B();
};

struct B { 
  B() { }
  B(A const&) { std::cout << "<direct> "; }
};

A::operator B() { std::cout << "<copy> "; return B(); }

int main() { 
  A a;
  B b1(a);  // 1)
  B b2 = a; // 2)
}
// output: <direct> <copy>

यह कैसे काम करता है, और इसका परिणाम क्यों होता है?

  1. प्रत्यक्ष आरंभीकरण

    यह पहले रूपांतरण के बारे में कुछ नहीं जानता है। यह सिर्फ एक निर्माता को कॉल करने का प्रयास करेगा। इस मामले में, निम्नलिखित कंस्ट्रक्टर उपलब्ध है और एक सटीक मिलान है :

    B(A const&)

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

  2. आरंभीकरण की प्रतिलिपि बनाएँ

    जैसा कि ऊपर कहा गया है, कॉपी इनिशियलाइज़ेशन एक रूपांतरण अनुक्रम का निर्माण करेगा जब aउससे टाइप Bया व्युत्पन्न नहीं हुआ है (जो स्पष्ट रूप से यहाँ मामला है)। तो यह रूपांतरण करने के तरीकों की तलाश करेगा, और निम्नलिखित उम्मीदवारों को ढूंढेगा

    B(A const&)
    operator B(A&);

    ध्यान दें कि मैंने रूपांतरण फ़ंक्शन को कैसे फिर से लिखा है: पैरामीटर प्रकार thisपॉइंटर के प्रकार को दर्शाता है , जो गैर-कॉन्स्टेबल सदस्य फ़ंक्शन में गैर-कॉन्स्टेंस के लिए है। अब, हम इन उम्मीदवारों xको तर्क के साथ बुलाते हैं । विजेता रूपांतरण फ़ंक्शन है: क्योंकि यदि हमारे पास दो उम्मीदवार कार्य हैं जो दोनों एक ही प्रकार के संदर्भ को स्वीकार करते हैं, तो कम कॉन्स्टेंस संस्करण जीतता है (इस तरह से, गैर-सदस्य सदस्य फ़ंक्शन को गैर के लिए प्राथमिकता देने वाला तंत्र भी गैर के लिए कहता है -संबंधी वस्तुएं)।

    ध्यान दें कि यदि हम रूपांतरण फ़ंक्शन को एक सदस्य सदस्य फ़ंक्शन के रूप में बदलते हैं, तो रूपांतरण अस्पष्ट है (क्योंकि दोनों में एक पैरामीटर प्रकार है A const&): कॉम्यू कंपाइलर इसे ठीक से अस्वीकार करता है, लेकिन जीसीसी इसे गैर-पांडित्यपूर्ण मोड में स्वीकार करता है। -pedanticयह उचित अस्पष्टता चेतावनी भी उत्पादन करने के लिए स्विचन हालांकि।

मुझे उम्मीद है कि यह कुछ हद तक यह स्पष्ट करने में मदद करता है कि ये दो रूप कैसे भिन्न हैं!


वाह। मुझे फ़ंक्शन घोषणा के बारे में भी पता नहीं चला। मुझे इस बारे में जानने के लिए केवल अपने उत्तर को स्वीकार करना है। क्या कोई कारण है कि फ़ंक्शन घोषणाएं उस तरह से काम करती हैं? यह बेहतर होगा यदि c3 को किसी फ़ंक्शन के अंदर अलग तरीके से व्यवहार किया जाता है।
आरएलबोंड

4
बाह, खेद लोग, लेकिन मैं नया स्वरूपण इंजन की वजह से मेरी टिप्पणी को हटा दें और इसे फिर से पोस्ट करने के लिए, था: यह क्योंकि समारोह मापदंडों में है, R() == R(*)()और T[] == T*। अर्थात्, फ़ंक्शन प्रकार फ़ंक्शन पॉइंटर प्रकार हैं, और सरणी प्रकार पॉइंटर-टू-एलिमेंट प्रकार हैं। यह बेकार है। इसके द्वारा काम किया जा सकता है A c3((A()));(अभिव्यक्ति के आस -पास )।
जोहान्स शाउब -

4
क्या मैं पूछ सकता हूं कि "" 8.5 / 14 पढ़ें "" का क्या मतलब है? इसका क्या मतलब है? एक किताब? एक अध्याय? एक वेबसाइट?
आजाद

9
@AzP एसओ पर कई लोग अक्सर C ++ युक्ति के संदर्भ चाहते हैं, और यही मैंने यहां किया है, rlbond के अनुरोध के जवाब में "कृपया प्रमाण के रूप में पाठ का हवाला दें।" मैं युक्ति का हवाला नहीं देना चाहता, क्योंकि वह मेरे जवाब को गलत ठहराती है और यह बहुत अधिक काम है कि वह तारीख (अतिरेक) को बरकरार रखे।
जोहान्स स्काउब -

1
@ लूका मैं एक नया प्रश्न शुरू करने के लिए पुनः आरंभ करता हूं ताकि अन्य लोग उत्तर देने वाले लोगों को लाभ दे सकें
जोहान्स स्काउब -

49

असाइनमेंट इनिशियलाइज़ेशन से अलग है

निम्नलिखित दोनों पंक्तियाँ आरंभीकरण करती हैं । एक एकल निर्माता कॉल किया जाता है:

A a1 = A_factory_func();  // calls copy constructor
A a1(A_factory_func());   // calls copy constructor

लेकिन यह इसके बराबर नहीं है:

A a1;                     // calls default constructor
a1 = A_factory_func();    // (assignment) calls operator =

मेरे पास यह साबित करने के लिए फिलहाल कोई पाठ नहीं है, लेकिन यह प्रयोग करना बहुत आसान है:

#include <iostream>
using namespace std;

class A {
public:
    A() { 
        cout << "default constructor" << endl;
    }

    A(const A& x) { 
        cout << "copy constructor" << endl;
    }

    const A& operator = (const A& x) {
        cout << "operator =" << endl;
        return *this;
    }
};

int main() {
    A a;       // default constructor
    A b(a);    // copy constructor
    A c = a;   // copy constructor
    c = b;     // operator =
    return 0;
}

2
अच्छा संदर्भ: "C ++ प्रोग्रामिंग लैंग्वेज, स्पेशल एडिशन" Bjarne Stroustrup द्वारा, सेक्शन 10.4.4.1 (पेज 245)। डिस्क्रिप्शन को कॉपी इनिशियलाइज़ेशन और कॉपी असाइनमेंट बताते हैं और वे मौलिक रूप से अलग क्यों हैं (हालांकि वे दोनों सिंटैक्स के रूप में = ऑपरेटर का उपयोग करते हैं)।
नाफ़

माइनर नाइट, लेकिन मुझे वास्तव में पसंद नहीं है जब लोग कहते हैं कि "ए ए (एक्स)" और "ए ए = एक्स" बराबर हैं। सख्ती से वे नहीं कर रहे हैं। बहुत सारे मामलों में वे बिल्कुल एक ही काम करेंगे, लेकिन ऐसे उदाहरण बनाना संभव है जहां तर्क के आधार पर विभिन्न निर्माणकर्ताओं को वास्तव में कहा जाता है।
रिचर्ड कॉर्डन

मैं "वाक्यविन्यास तुल्यता" के बारे में बात नहीं कर रहा हूँ। शब्दार्थ, आरंभ के दोनों तरीके समान हैं।
मेहरदाद अफश्री

@MehrdadAfshari जोहान्स के जवाब के कोड में आपको अलग-अलग आउटपुट मिलते हैं, जिनके आधार पर आप दोनों का उपयोग करते हैं।
ब्रायन गॉर्डन

1
@BrianGordon हाँ, तुम सही हो। वे समकक्ष नहीं हैं। मैंने बहुत पहले ही अपने संपादन में रिचर्ड की टिप्पणी को संबोधित किया था।
मेहरदाद अफश्री

22

double b1 = 0.5; कंस्ट्रक्टर की निहित कॉल है।

double b2(0.5); स्पष्ट कॉल है।

अंतर देखने के लिए निम्न कोड देखें:

#include <iostream>
class sss { 
public: 
  explicit sss( int ) 
  { 
    std::cout << "int" << std::endl;
  };
  sss( double ) 
  {
    std::cout << "double" << std::endl;
  };
};

int main() 
{ 
  sss ddd( 7 ); // calls int constructor 
  sss xxx = 7;  // calls double constructor 
  return 0;
}

यदि आपकी कक्षा में स्पष्ट और अंतर्निहित कॉल की तुलना में कोई स्पष्ट अवरोधक नहीं हैं, तो समान हैं।


5
+1। अच्छा उत्तर। अच्छा भी स्पष्ट संस्करण पर ध्यान दें। वैसे, यह ध्यान रखना महत्वपूर्ण है कि आपके पास एक ही समय में एक ही निर्माण अधिभार के दोनों संस्करण नहीं हो सकते हैं । इसलिए, यह स्पष्ट मामले में संकलित करने में विफल होगा। यदि वे दोनों संकलन करते हैं, तो उन्हें समान व्यवहार करना होगा।
मेहरदाद अफश्री

4

पहला समूहन: यह इस बात पर निर्भर करता है कि A_factory_funcकौनसा रिटर्न है। पहली पंक्ति प्रतिलिपि आरंभीकरण का एक उदाहरण है , दूसरी पंक्ति प्रत्यक्ष आरंभीकरण है । यदि A_factory_funcकोई Aवस्तु वापस आती है तो वे समतुल्य होती हैं, वे दोनों कॉपी कंस्ट्रक्टर को कॉल करते हैं A, अन्यथा पहले संस्करण Aवापसी प्रकार A_factory_funcया उपयुक्त Aकंस्ट्रक्टरों के लिए उपलब्ध रूपांतरण ऑपरेटरों से टाइप का एक रव्वा बनाता है , और फिर a1इस से निर्माण करने के लिए कॉपी कंस्ट्रक्टर को कॉल करता है अस्थायी। दूसरा संस्करण एक उपयुक्त निर्माणकर्ता को खोजने का प्रयास करता है जो कुछ भी A_factory_funcरिटर्न लेता है, या जो कुछ ऐसा लेता है जो वापसी मूल्य को संक्षेप में परिवर्तित कर सकता है।

दूसरा समूहीकरण: वास्तव में एक ही तर्क रखता है, सिवाय इसके कि प्रकारों में निर्मित कोई भी बाहरी निर्माणकर्ता नहीं है, इसलिए वे व्यवहार में समान हैं।

तीसरा समूहीकरण: c1डिफ़ॉल्ट आरंभिक है, c2अस्थायी रूप से आरंभिक मूल्य से कॉपी-आरंभ किया जाता है। किसी भी सदस्य के c1पास फली-प्रकार (या सदस्यों के सदस्यों, आदि, आदि) को प्रारंभ नहीं किया जा सकता है यदि उपयोगकर्ता डिफ़ॉल्ट निर्माणकर्ताओं (यदि कोई हो) की आपूर्ति स्पष्ट रूप से उन्हें प्रारंभ नहीं करता है। इसके लिए c2, यह इस बात पर निर्भर करता है कि क्या कोई उपयोगकर्ता आपूर्ति की गई कॉपी निर्माता है और क्या यह उचित रूप से उन सदस्यों को आरंभिक करता है, लेकिन अस्थायी के सदस्यों को प्रारंभिक रूप से परिभाषित किया जाएगा (शून्य-आरंभिक रूप से अन्यथा स्पष्ट रूप से प्रारंभिक नहीं)। जैसा कि litb स्पॉट किया गया, c3एक जाल है। यह वास्तव में एक फ़ंक्शन घोषणा है।


4

टिप्पणी का:

[12.2 / 1] Temporaries of class type are created in various contexts: ... and in some initializations (8.5).

यानी, कॉपी-इनिशियलाइजेशन के लिए।

[12.8 / 15] When certain criteria are met, an implementation is allowed to omit the copy construction of a class object ...

दूसरे शब्दों में, एक अच्छा संकलक कॉपी-आरंभीकरण के लिए एक प्रतिलिपि नहीं बनाएगा जब इसे टाला जा सकता है; इसके बजाय यह सीधे-सीधे निर्माणकर्ता को बुलाएगा - यानी, प्रत्यक्ष-आरंभ के लिए।

दूसरे शब्दों में, कॉपी-इनिशियलाइज़ेशन ज्यादातर मामलों में प्रत्यक्ष-आरंभीकरण की तरह है <राय> जहां समझने योग्य कोड लिखा गया है। चूंकि प्रत्यक्ष-आरंभीकरण संभावित रूप से मनमाना (और इसलिए शायद अज्ञात) रूपांतरणों का कारण बनता है, मैं हमेशा जब संभव हो तो कॉपी-आरंभीकरण का उपयोग करना पसंद करता हूं। (बोनस के साथ कि यह वास्तव में आरंभीकरण जैसा दिखता है।) </ राय>

तकनीकी नौटंकी: [१२.२ / १ ऊपर से प्रतियोगिता] Even when the creation of the temporary object is avoided (12.8), all the semantic restrictions must be respected as if the temporary object was created.

खुशी है कि मैं C ++ कंपाइलर नहीं लिख रहा हूं।


4

जब आप किसी ऑब्जेक्ट को प्रारंभ करते हैं तो आप उसके explicitऔर implicitकंस्ट्रक्टर प्रकारों में अंतर देख सकते हैं :

कक्षाएं:

class A
{
    A(int) { }      // converting constructor
    A(int, int) { } // converting constructor (C++11)
};

class B
{
    explicit B(int) { }
    explicit B(int, int) { }
};

और main समारोह में:

int main()
{
    A a1 = 1;      // OK: copy-initialization selects A::A(int)
    A a2(2);       // OK: direct-initialization selects A::A(int)
    A a3 {4, 5};   // OK: direct-list-initialization selects A::A(int, int)
    A a4 = {4, 5}; // OK: copy-list-initialization selects A::A(int, int)
    A a5 = (A)1;   // OK: explicit cast performs static_cast

//  B b1 = 1;      // error: copy-initialization does not consider B::B(int)
    B b2(2);       // OK: direct-initialization selects B::B(int)
    B b3 {4, 5};   // OK: direct-list-initialization selects B::B(int, int)
//  B b4 = {4, 5}; // error: copy-list-initialization does not consider B::B(int,int)
    B b5 = (B)1;   // OK: explicit cast performs static_cast
}

डिफ़ॉल्ट रूप से, एक कंस्ट्रक्टर ऐसा है जैसा implicitकि आपके पास इसे आरंभ करने के लिए दो तरीके हैं:

A a1 = 1;        // this is copy initialization
A a2(2);         // this is direct initialization

और एक संरचना को परिभाषित करते हुए जैसे explicitकि आपके पास प्रत्यक्ष के रूप में एक ही रास्ता है:

B b2(2);        // this is direct initialization
B b5 = (B)1;    // not problem if you either use of assign to initialize and cast it as static_cast

3

इस भाग के संबंध में उत्तर देना:

ए सी 2 = ए (); ए सी 3 (ए) ();

चूँकि अधिकतर उत्तर प्री-सी ++ 11 हैं, इसलिए मैं इस बारे में सी +11 का क्या कहना है, जोड़ रहा हूँ:

एक साधारण-प्रकार-विनिर्देशक (7.1.6.2) या टाइप-नेम-स्पेसियर (14.6) के बाद एक कोष्ठक-अभिव्यक्ति अभिव्यक्ति-सूची निर्दिष्ट प्रकार के एक मूल्य का निर्माण करती है जिसे अभिव्यक्ति सूची दी गई है। यदि अभिव्यक्ति सूची एक एकल अभिव्यक्ति है, तो टाइप रूपांतरण अभिव्यक्ति समतुल्य कास्ट एक्सप्रेशन (5.4) में समतुल्य (परिभाषितता में, और यदि अर्थ में परिभाषित है) है। यदि निर्दिष्ट प्रकार एक वर्ग प्रकार है, तो वर्ग प्रकार पूरा हो जाएगा। यदि अभिव्यक्ति सूची एक से अधिक मान निर्दिष्ट करती है, तो प्रकार एक वर्ग के साथ उपयुक्त घोषित निर्माता (8.5, 12.1) होगा, और अभिव्यक्ति T (X1, x2, ...) घोषणा टी के प्रभाव के बराबर है। (एक्स 1, एक्स 2, ...); कुछ आविष्कार किए गए अस्थायी चर टी के लिए, जिसके परिणामस्वरूप टी के मूल्य के रूप में एक मूल्य है।

इसलिए अनुकूलन या नहीं वे मानक के अनुसार समान हैं। ध्यान दें कि यह अन्य उत्तर के अनुसार है। केवल यह कहते हुए कि मानक को सही होने के लिए क्या कहना है।


आपके उदाहरणों में से कोई भी "अभिव्यक्ति सूची एक से अधिक मूल्य निर्दिष्ट नहीं करता है"। यह कैसे प्रासंगिक है?
अंडरस्कोर_ड

0

इनमें से बहुत सारे मामले एक वस्तु के कार्यान्वयन के अधीन हैं, इसलिए आपको ठोस जवाब देना मुश्किल है।

मामले पर विचार करें

A a = 5;
A a(5);

इस मामले में एक उचित असाइनमेंट ऑपरेटर और इनिशियलाइज़िंग कंस्ट्रक्टर मान रहा है जो एक पूर्णांक तर्क को स्वीकार करता है, मैं कैसे लागू करता हूं कि कहा गया है कि प्रत्येक लाइन के व्यवहार को प्रभावित करता है। हालाँकि कार्यान्वयन में दूसरे को कॉल करने के लिए सामान्य रूप से यह है कि डुप्लिकेट कोड को समाप्त करने के लिए (हालांकि एक मामले में यह उतना ही सरल है जितना कोई वास्तविक उद्देश्य नहीं होगा।)

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

उस ने कहा, कैसे संकलक कोड का अनुकूलन करता है तो इसका अपना प्रभाव होगा। यदि मेरे पास प्रारंभिक = "ऑपरेटर" ऑपरेटर को कॉल करने वाला है - यदि संकलक कोई अनुकूलन नहीं करता है, तो शीर्ष रेखा फिर नीचे की पंक्ति में एक के विपरीत 2 कूदता है।

अब, सबसे सामान्य स्थितियों के लिए, आपका संकलक इन मामलों के माध्यम से अनुकूलन करेगा और इस प्रकार की अक्षमताओं को समाप्त करेगा। तो प्रभावी रूप से आपके द्वारा वर्णित सभी अलग-अलग स्थितियों को एक समान कर देगा। यदि आप वास्तव में देखना चाहते हैं कि क्या किया जा रहा है, तो आप ऑब्जेक्ट कोड या अपने कंपाइलर के असेंबली आउटपुट को देख सकते हैं।


यह एक अनुकूलन नहीं है । कंपाइलर को दोनों मामलों में कंस्ट्रक्टर को समान रूप से कॉल करना होगा। नतीजतन, उनमें से कोई भी संकलन नहीं करेगा यदि आपके पास बस है operator =(const int)और नहीं A(const int)। अधिक जानकारी के लिए @ jia3ep का उत्तर देखें।
मेहरदाद अफशरी

मेरा मानना ​​है कि आप वास्तव में सही हैं। हालांकि यह एक डिफ़ॉल्ट कॉपी कंस्ट्रक्टर का उपयोग करके बस ठीक संकलन करेगा।
21

इसके अलावा, जैसा कि मैंने उल्लेख किया है, एक कॉपी कंस्ट्रक्टर को एक असाइनमेंट ऑपरेटर को कॉल करना आम बात है, जिस बिंदु पर संकलक अनुकूलन खेलने पर आते हैं।
dborba

0

यह C ++ प्रोग्रामिंग लैंग्वेज Bjarne Stroustrup से है:

एक = के साथ एक आरंभीकरण एक प्रतिलिपि आरंभीकरण माना जाता है । सिद्धांत रूप में, इनिशलाइज़र की एक प्रति (जिस ऑब्जेक्ट से हम कॉपी कर रहे हैं) को इनिशियलाइज़्ड ऑब्जेक्ट में रखा जाता है। हालाँकि, इस तरह की प्रतिलिपि को दूर किया जा सकता है (elided), और एक चालन कार्रवाई (चाल शब्दार्थ के आधार पर) का उपयोग किया जा सकता है यदि इनिशियलाइज़र एक प्रतिद्वंद्विता है। बाहर छोड़ना = आरंभ को स्पष्ट करता है। स्पष्ट आरंभीकरण को प्रत्यक्ष आरंभीकरण के रूप में जाना जाता है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.