C ++ 11 में T && (डबल एम्परसेंड) का क्या अर्थ है?


799

मैं C ++ 11 की कुछ नई विशेषताओं को देख रहा हूं और मैंने देखा है कि चर, जैसे घोषित करने में डबल एम्परसेंड है T&& var

एक शुरुआत के लिए, इस जानवर को क्या कहा जाता है? काश गूगल हमें इस तरह विराम चिह्न की खोज करने की अनुमति देता।

वास्तव में इसका क्या मतलब है?

पहली नज़र में, यह एक डबल संदर्भ (सी-स्टाइल डबल पॉइंटर्स की तरह T** var) प्रतीत होता है , लेकिन मैं इसके लिए उपयोग के मामले में एक कठिन समय सोच रहा हूं।


55
मैंने इसे c ++ - faq में जोड़ा है, क्योंकि मुझे यकीन है कि यह भविष्य में और अधिक आएगा।
GManNickG


41
आप Google का उपयोग करके इसे खोज सकते हैं, आपको केवल अपने वाक्यांश को उद्धरणों में लपेटना होगा: google.com/#q="T%26%26 "अब आपके सवाल का पहला हिट है। :)
sbi

ऐसे ही एक सवाल का जवाब समझने में बहुत अच्छा, आसान है यहां stackoverflow.com/questions/7153991/…
डैनियल

2
मुझे "c ++ दो एम्परसेंड्स पैरामीटर" के लिए Google में शीर्ष खोज पर तीन स्टैकओवरफ़्लो प्रश्न मिले और आपका पहला था। इसलिए आपको इसके लिए विराम चिह्नों का उपयोग करने की आवश्यकता नहीं है यदि आप "दो एम्परसेंड्स पैरामीटर" वर्तनी कर सकते हैं।
सर्गियोल

जवाबों:


668

यह एक अवतरण संदर्भ (मानक प्रस्ताव डॉक्टर) की घोषणा करता है ।

यहाँ संदर्भों का परिचय दिया गया है ।

यहाँ Microsoft के मानक लाइब्रेरी डेवलपर्स में से एक के संदर्भ में शानदार नज़र है

चेतावनी: MSDN पर लिंक लेख ("Rvalue References: C ++ 0x विशेषताएँ VC10 में, भाग 2") Rvalue संदर्भों के लिए एक बहुत ही स्पष्ट परिचय है, लेकिन Rvalue संदर्भों के बारे में बयान करता है जो एक बार ड्राफ्ट + 11 में सही थे। मानक, लेकिन अंतिम एक के लिए सच नहीं हैं! विशेष रूप से, यह विभिन्न बिंदुओं पर कहता है कि प्रतिद्वंद्वियों के संदर्भ अंतरालों को बांध सकते हैं, जो एक बार सच था, लेकिन बदल गया था (उदाहरण के लिए; int && rrx = x; अब जीसीसी में संकलित नहीं) - drewbsbs Jul 13 '14 16:12 पर;

C ++ 03 सन्दर्भ (अब C ++ 11 में एक लवल्यू रेफरेंस कहा जाता है) के बीच सबसे बड़ा अंतर यह है कि यह एक अस्थाई की तरह एक रव्वा को बाँध सकता है, जिसमें कॉन्स्टेबल न हों। इस प्रकार, यह वाक्यविन्यास अब कानूनी है:

T&& r = T();

rvalue संदर्भ मुख्य रूप से निम्नलिखित के लिए प्रदान करते हैं:

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

उदाहरण के लिए, एक प्रतिलिपि निर्माता इस तरह दिख सकता है:

foo(foo const& other)
{
    this->length = other.length;
    this->ptr = new int[other.length];
    copy(other.ptr, other.ptr + other.length, this->ptr);
}

यदि यह निर्माता अस्थायी रूप से पारित किया गया था, तो प्रतिलिपि अनावश्यक होगी क्योंकि हम जानते हैं कि अस्थायी बस नष्ट हो जाएगी; अस्थायी पहले से आवंटित संसाधनों का उपयोग क्यों नहीं करते? C ++ 03 में, प्रतिलिपि को रोकने का कोई तरीका नहीं है क्योंकि हम यह निर्धारित नहीं कर सकते कि हम एक अस्थायी पारित किए गए थे। C ++ 11 में, हम एक चाल निर्माणकर्ता को अधिभारित कर सकते हैं:

foo(foo&& other)
{
   this->length = other.length;
   this->ptr = other.ptr;
   other.length = 0;
   other.ptr = nullptr;
}

यहां बड़े अंतर पर ध्यान दें: चाल निर्माणकर्ता वास्तव में अपने तर्क को संशोधित करता है। यह प्रभावी रूप से निर्माण की जा रही वस्तु में अस्थायी रूप से "स्थानांतरित" करेगा, जिससे अनावश्यक प्रतिलिपि समाप्त हो जाएगी।

चाल निर्माणकर्ता का उपयोग अस्थायी लोगों के लिए और गैर-कॉन्स्टल लैवल्यू संदर्भों के लिए किया जाएगा जो स्पष्ट रूप से std::moveफ़ंक्शन का उपयोग करके संदर्भ संदर्भों में परिवर्तित हो जाते हैं (यह सिर्फ रूपांतरण करता है)। निम्नलिखित कोड दोनों के लिए कदम निर्माता आह्वान f1और f2:

foo f1((foo())); // Move a temporary into f1; temporary becomes "empty"
foo f2 = std::move(f1); // Move f1 into f2; f1 is now "empty"

एकदम सही अग्रेषण । rvalue के संदर्भ हमें अस्थायी कार्यों के लिए ठीक से तर्क देने की अनुमति देते हैं। उदाहरण के लिए इस कारखाने समारोह:

template <typename T, typename A1>
std::unique_ptr<T> factory(A1& a1)
{
    return std::unique_ptr<T>(new T(a1));
}

अगर हम कहते हैं factory<foo>(5), तो तर्क को घटा दिया जाएगा int&, जो कि शाब्दिक 5 से नहीं बंधेगा, भले ही fooनिर्माता एक लेता हो int। ठीक है, हम इसके बजाय उपयोग कर सकते हैं A1 const&, लेकिन क्या होगा यदि fooगैर-कॉन्स्टेंस संदर्भ द्वारा निर्माता तर्क लेता है? वास्तव में एक सामान्य कारखाने समारोह बनाने के लिए हम पर कारखाने ओवरलोड करने के लिए होता A1&है और पर A1 const&। यदि कारखाना 1 पैरामीटर प्रकार लेता है, तो यह ठीक हो सकता है, लेकिन प्रत्येक अतिरिक्त पैरामीटर प्रकार 2. द्वारा निर्धारित आवश्यक अधिभार को गुणा करेगा। यह बहुत जल्दी अप्राप्य है।

मानक लाइब्रेरी को किसी std::forwardफ़ंक्शन को परिभाषित करने की अनुमति देकर इस समस्या को ठीक करता है, जो कि रेवल्यू / रेवल्यू संदर्भों को ठीक से अग्रेषित कर सकता है। कैसे std::forwardकाम करता है, इसके बारे में अधिक जानकारी के लिए , यह उत्कृष्ट उत्तर देखें ।

यह हमें कारखाने के कार्य को इस तरह परिभाषित करने में सक्षम बनाता है:

template <typename T, typename A1>
std::unique_ptr<T> factory(A1&& a1)
{
    return std::unique_ptr<T>(new T(std::forward<A1>(a1)));
}

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

जब फंक्शन पैरामीटर टाइप उस प्रकार का होता है, T&&जहां Tटेम्पलेट पैरामीटर होता है, और फ़ंक्शन तर्क प्रकार का एक अंतराल होता है A, तो टाइप A&का उपयोग टेम्पलेट तर्क कटौती के लिए किया जाता है।

इस प्रकार, हम कारखाने का उपयोग कर सकते हैं जैसे:

auto p1 = factory<foo>(foo()); // calls foo(foo&&)
auto p2 = factory<foo>(*p1);   // calls foo(foo const&)

महत्वपूर्ण संदर्भ संदर्भ गुण :

  • अधिभार संकल्प के लिए, लवलेव्स रेवल्यू संदर्भों के लिए बाध्यकारी पसंद करते हैं और रिवेल्यूज़ रैवल्यू संदर्भों के लिए बाइंडिंग पसंद करते हैं । इसलिए अस्थायी लोग कॉपी कंस्ट्रक्टर / असाइनमेंट ऑपरेटर के ऊपर मूव कंस्ट्रक्टर / मूव असाइनमेंट ऑपरेटर को इनवॉइस करना पसंद करते हैं।
  • rvalue सन्दर्भ निहितार्थों से और अस्थायी तौर पर बंधे होंगे जो एक अंतर्निहित रूपांतरण का परिणाम हैं । यानी float f = 0f; int&& i = f;अच्छी तरह से बनता है क्योंकि फ्लोट का तात्पर्य अंतर से आंतरिक में होता है; संदर्भ एक अस्थायी होगा जो रूपांतरण का परिणाम है।
  • नामित रूवेल्यू संदर्भ लैवल हैं। अनाम: अवतरण संदर्भ rvalues ​​हैं। यह समझना महत्वपूर्ण है कि इसमें std::moveकॉल क्यों आवश्यक है:foo&& r = foo(); foo f = std::move(r);

65
+1 के लिए Named rvalue references are lvalues. Unnamed rvalue references are rvalues.; यह जानने के बिना कि मैं यह समझने के लिए संघर्ष कर रहा हूं कि लोग T &&t; std::move(t);एक लंबे समय के लिए कदम रखने वालों और इस तरह से क्यों करते हैं।
किंवदंतियां 2

@MaximYegorushkin: उस उदाहरण में, r एक शुद्ध अंतराल (अस्थायी) के लिए बाध्य है और इसलिए अस्थायी को अपने जीवनकाल का दायरा बढ़ाया जाना चाहिए, नहीं?
पीटर ह्यूने जूल

@PeterHuene मैं इसे वापस लेता हूं, एक आर-मूल्य संदर्भ एक अस्थायी जीवनकाल का विस्तार करता है।
मैक्सिम एगोरुस्किन जूल

32
चेतावनी : MSDN ( "rvalue संदर्भ: C ++ 0x VC10, भाग 2 में सुविधाएं") पर जुड़ा हुआ लेख है rvalue संदर्भ के लिए एक बहुत ही स्पष्ट परिचय, लेकिन है कि थे rvalue संदर्भ के बारे में बयान करता है एक बार सच मसौदा सी ++ 11 में मानक, लेकिन अंतिम एक के लिए सच नहीं हैं ! विशेष रूप से, यह विभिन्न बिंदुओं पर कहता है कि प्रतिद्वंद्विता के संदर्भ अंतराल के लिए बाध्य हो सकते हैं, जो एक बार सच था , लेकिन बदल दिया गया था । (उदाहरण के लिए जीसीसी में int x; int &&rrx = x; अब संकलित नहीं )
drewbarbs

@PeterHuene उपरोक्त उदाहरण में, के typename identity<T>::type& aबराबर नहीं है T&?
ibp73

81

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

C ++ 03 में, आप एक गैर-उत्परिवर्ती अंतराल और एक प्रतिद्वंद्विता की एक प्रति के बीच अंतर नहीं कर सकते।

std::string s;
std::string another(s);           // calls std::string(const std::string&);
std::string more(std::string(s)); // calls std::string(const std::string&);

C ++ 0x में, यह मामला नहीं है।

std::string s;
std::string another(s);           // calls std::string(const std::string&);
std::string more(std::string(s)); // calls std::string(std::string&&);

इन निर्माणकर्ताओं के पीछे के कार्यान्वयन पर विचार करें। पहले मामले में, स्ट्रिंग को मूल्य शब्दार्थ को बनाए रखने के लिए एक प्रति प्रदर्शन करना है, जिसमें एक नया ढेर आवंटन शामिल है। हालांकि, दूसरे मामले में, हम पहले से जानते हैं कि हमारे निर्माणकर्ता को जो वस्तु पारित की गई थी, वह विनाश के कारण तुरंत है, और इसे अछूता नहीं रहना है। हम आंतरिक बिंदुओं को प्रभावी ढंग से स्वैप कर सकते हैं और इस परिदृश्य में बिल्कुल भी नकल नहीं कर सकते हैं, जो काफी अधिक कुशल है। चालित शब्दार्थ किसी भी वर्ग को लाभान्वित करता है जिसके पास आंतरिक रूप से संदर्भित संसाधनों की महंगी या निषिद्ध नकल है। के मामले पर विचार करें std::unique_ptr- अब जब हमारी कक्षा अस्थायी और गैर-अस्थायी के बीच अंतर कर सकती है, तो हम चाल शब्दार्थ को सही ढंग से काम unique_ptrकर सकते हैं ताकि नकल न की जा सके लेकिन इसे स्थानांतरित किया जा सकता है, जिसका अर्थ है किstd::unique_ptrकानूनी रूप से मानक कंटेनरों में संग्रहित किया जा सकता है, आदि, जबकि C ++ 03 का std::auto_ptrनहीं।

अब हम रवैल्यू रेफरेंस के दूसरे उपयोग पर विचार करते हैं- परफेक्ट फॉरवर्डिंग। एक संदर्भ के संदर्भ को बांधने के प्रश्न पर विचार करें।

std::string s;
std::string& ref = s;
(std::string&)& anotherref = ref; // usually expressed via template

याद नहीं कर सकते कि C ++ 03 इस बारे में क्या कहता है, लेकिन C ++ 0x में परिणामी प्रकार, जब रवैल्यू रेफरेंस से निपटना महत्वपूर्ण होता है। एक प्रकार टी के लिए एक संदर्भ संदर्भ, जहां टी एक संदर्भ प्रकार है, टाइप टी का संदर्भ बन जाता है।

(std::string&)&& ref // ref is std::string&
(const std::string&)&& ref // ref is const std::string&
(std::string&&)&& ref // ref is std::string&&
(const std::string&&)&& ref // ref is const std::string&&

सबसे सरल टेम्पलेट फ़ंक्शन पर विचार करें- न्यूनतम और अधिकतम। C ++ 03 में आपको कॉन्स्टल और नॉन-कास्ट के सभी चार संयोजनों को मैन्युअल रूप से ओवरलोड करना होगा। C ++ 0x में यह केवल एक अधिभार है। वैरेडिक टेम्प्लेट के साथ संयुक्त, यह सही अग्रेषण को सक्षम करता है।

template<typename A, typename B> auto min(A&& aref, B&& bref) {
    // for example, if you pass a const std::string& as first argument,
    // then A becomes const std::string& and by extension, aref becomes
    // const std::string&, completely maintaining it's type information.
    if (std::forward<A>(aref) < std::forward<B>(bref))
        return std::forward<A>(aref);
    else
        return std::forward<B>(bref);
}

मैंने रिटर्न प्रकार कटौती को छोड़ दिया, क्योंकि मैं याद नहीं कर सकता कि यह कैसे ऑफहैंड किया गया है, लेकिन वह मिनट किसी भी प्रकार के अंतराल, अंतराल, कॉन्स्टल लेवल को स्वीकार कर सकता है।


आपने उपयोग क्यों किया std::forward<A>(aref) < std::forward<B>(bref)? और मुझे नहीं लगता है कि जब आप आगे की कोशिश इस परिभाषा सही हो जाएगा int&और float&। एक प्रकार के टेम्पलेट को बेहतर तरीके से छोड़ें।
येंकेज़

25

T&& टाइप डिडक्शन (जैसे परफेक्ट फॉरवर्डिंग के लिए) के साथ प्रयोग किए जाने के लिए शब्द आम तौर पर एक अग्रेषण संदर्भ के रूप में जाना जाता है । "सार्वभौमिक संदर्भ" शब्द इस आलेख में स्कॉट मेयर्स द्वारा गढ़ा गया था , लेकिन बाद में बदल दिया गया था।

ऐसा इसलिए है क्योंकि यह या तो आर-मूल्य या एल-मूल्य हो सकता है।

उदाहरण हैं:

// template
template<class T> foo(T&& t) { ... }

// auto
auto&& t = ...;

// typedef
typedef ... T;
T&& t = ...;

// decltype
decltype(...)&& t = ...;

अधिक चर्चा इसके उत्तर में मिल सकती है: सार्वभौमिक संदर्भों के लिए सिंटैक्स


14

एक रेवल्यू संदर्भ एक प्रकार है जो कई अपवादों के साथ सामान्य संदर्भ एक्स एंड की तरह व्यवहार करता है। सबसे महत्वपूर्ण यह है कि जब यह ओवरलोड रिज़ॉल्यूशन की बात आती है, तो लैवल्स पुराने स्टाइल के लैवल्यू रेफरेंस को पसंद करते हैं, जबकि रिवेल्यूज़ नए रिवैल्यू रेफरेंस को पसंद करते हैं:

void foo(X& x);  // lvalue reference overload
void foo(X&& x); // rvalue reference overload

X x;
X foobar();

foo(x);        // argument is lvalue: calls foo(X&)
foo(foobar()); // argument is rvalue: calls foo(X&&)

तो एक प्रतिद्वंद्विता क्या है? कोई भी चीज जो लवलीन नहीं है। एक लवल्यू एक अभिव्यक्ति है जो एक मेमोरी लोकेशन को संदर्भित करता है और हमें उस मेमोरी लोकेशन का पता & ऑपरेटर के माध्यम से लेने की अनुमति देता है।

यह समझना सबसे आसान है कि पहले उदाहरण के साथ कौन-कौन से परिणाम मिलते हैं:

 #include <cstring>
 class Sample {
  int *ptr; // large block of memory
  int size;
 public:
  Sample(int sz=0) : ptr{sz != 0 ? new int[sz] : nullptr}, size{sz} 
  {
     if (ptr != nullptr) memset(ptr, 0, sz);
  }
  // copy constructor that takes lvalue 
  Sample(const Sample& s) : ptr{s.size != 0 ? new int[s.size] :\
      nullptr}, size{s.size}
  {
     if (ptr != nullptr) memcpy(ptr, s.ptr, s.size);
     std::cout << "copy constructor called on lvalue\n";
  }

  // move constructor that take rvalue
  Sample(Sample&& s) 
  {  // steal s's resources
     ptr = s.ptr;
     size = s.size;        
     s.ptr = nullptr; // destructive write
     s.size = 0;
     cout << "Move constructor called on rvalue." << std::endl;
  }    
  // normal copy assignment operator taking lvalue
  Sample& operator=(const Sample& s)
  {
   if(this != &s) {
      delete [] ptr; // free current pointer
      size = s.size;

      if (size != 0) {
        ptr = new int[s.size];
        memcpy(ptr, s.ptr, s.size);
      } else 
         ptr = nullptr;
     }
     cout << "Copy Assignment called on lvalue." << std::endl;
     return *this;
  }    
 // overloaded move assignment operator taking rvalue
 Sample& operator=(Sample&& lhs)
 {
   if(this != &s) {
      delete [] ptr; //don't let ptr be orphaned 
      ptr = lhs.ptr;   //but now "steal" lhs, don't clone it.
      size = lhs.size; 
      lhs.ptr = nullptr; // lhs's new "stolen" state
      lhs.size = 0;
   }
   cout << "Move Assignment called on rvalue" << std::endl;
   return *this;
 }
//...snip
};     

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

कंपाइलर स्वचालित रूप से संकलित समय पर शाखाएं करता है (यह निर्भर करता है कि क्या यह एक लेवल्यू या रिवेल्यू के लिए इनवाइट किया जा रहा है) यह चुनने के लिए कि क्या मूव कंस्ट्रक्टर या मूव असाइनमेंट ऑपरेटर को बुलाया जाना चाहिए।

सारांश: संदर्भ के संदर्भ में शब्दार्थ को स्थानांतरित करने की अनुमति है (और सही अग्रेषण, नीचे दिए गए लेख लिंक में चर्चा की गई है)।

एक व्यावहारिक आसान-से-समझने वाला उदाहरण कक्षा टेम्पलेट std :: unique_ptr है । चूँकि एक यूनिक_प्रटर अपने अंतर्निहित कच्चे पॉइंटर के अनन्य स्वामित्व को बनाए रखता है, इसलिए यूनिक_प्रटर की नकल नहीं की जा सकती। यह उनके विशेष स्वामित्व के अपरिवर्तनीय उल्लंघन होगा। इसलिए उनके पास कॉपी कंस्ट्रक्टर नहीं हैं। लेकिन उनके पास निर्माणकर्ता नहीं हैं:

template<class T> class unique_ptr {
  //...snip
 unique_ptr(unique_ptr&& __u) noexcept; // move constructor
};

 std::unique_ptr<int[] pt1{new int[10]};  
 std::unique_ptr<int[]> ptr2{ptr1};// compile error: no copy ctor.  

 // So we must first cast ptr1 to an rvalue 
 std::unique_ptr<int[]> ptr2{std::move(ptr1)};  

std::unique_ptr<int[]> TakeOwnershipAndAlter(std::unique_ptr<int[]> param,\
 int size)      
{
  for (auto i = 0; i < size; ++i) {
     param[i] += 10;
  }
  return param; // implicitly calls unique_ptr(unique_ptr&&)
}

// Now use function     
unique_ptr<int[]> ptr{new int[10]};

// first cast ptr from lvalue to rvalue
unique_ptr<int[]> new_owner = TakeOwnershipAndAlter(\
           static_cast<unique_ptr<int[]>&&>(ptr), 10);

cout << "output:\n";

for(auto i = 0; i< 10; ++i) {
   cout << new_owner[i] << ", ";
}

output:
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 

static_cast<unique_ptr<int[]>&&>(ptr)आमतौर पर एसटीडी :: चाल का उपयोग करके किया जाता है

// first cast ptr from lvalue to rvalue
unique_ptr<int[]> new_owner = TakeOwnershipAndAlter(std::move(ptr),0);

यह सब और अधिक व्याख्या करने वाला एक उत्कृष्ट लेख (जैसे कि कैसे प्रतिद्वंद्विता सही अग्रेषण की अनुमति देती है और इसका क्या मतलब है) बहुत सारे अच्छे उदाहरणों के साथ थॉमस बेकर के सी ++ रिव्यू सन्दर्भ को समझाया गया है । यह पोस्ट उनके लेख पर बहुत निर्भर करता था।

एक छोटा परिचय स्ट्राउटरूप, एट द्वारा एक संक्षिप्त परिचय है । अल


क्या ऐसा नहीं है कि सामग्री की प्रतिलिपि बनाने के लिए प्रतिलिपि निर्माता Sample(const Sample& s)की भी आवश्यकता है? 'कॉपी असाइनमेंट ऑपरेटर' के लिए भी यही सवाल है।
करमाज़ेन

हाँ आप सही है। मैं मेमोरी कॉपी करने में विफल रहा। कॉपी कंस्ट्रक्टर और कॉपी असाइनमेंट ऑपरेटर दोनों को उस साइज़ को टेस्ट करने के बाद मेम्कपी (ptr, s.ptr, साइज़) करना चाहिए! = 0. और डिफॉल्ट कंस्ट्रक्टर को साइज़ (ptr, 0, साइज़) करना चाहिए अगर साइज़! = 0.
कर्टेन krueckeberg

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