एग्रीगेट और पीओडी क्या हैं और वे कैसे / विशेष क्यों हैं?


548

यह FAQ एग्रिगेट्स और पीओडी के बारे में है और निम्नलिखित सामग्री को शामिल करता है:

  • समुच्चय क्या हैं ?
  • POD s (Plain Old Data) क्या हैं ?
  • वे कैसे संबंधित हैं?
  • वे कैसे और क्यों खास हैं?
  • C ++ 11 के लिए क्या परिवर्तन हैं?


क्या यह कहा जा सकता है कि इन परिभाषाओं के पीछे प्रेरणा मोटे तौर पर है: POD == memcpy'able, Aggregate == कुल-प्रारंभिक?
तोक शीलोन

जवाबों:


571

कैसे पढ़ें:

यह लेख बल्कि लंबा है। यदि आप दोनों समुच्चय और POD (Plain Old Data) के बारे में जानना चाहते हैं तो समय निकालें और इसे पढ़ें। यदि आप केवल समुच्चय में रुचि रखते हैं, तो केवल पहले भाग को पढ़ें। यदि आप केवल PODs में रुचि रखते हैं तो आपको पहले समुच्चय की परिभाषा, निहितार्थ और उदाहरण पढ़ना चाहिए और फिर आप POD में कूद सकते हैं लेकिन मैं फिर भी इसकी संपूर्णता में पहला भाग पढ़ने की सलाह दूंगा। PODs को परिभाषित करने के लिए समुच्चय की धारणा आवश्यक है। यदि आपको कोई त्रुटि मिलती है (व्याकरण, शैलीविज्ञान, स्वरूपण, वाक्य रचना, आदि सहित मामूली भी) तो कृपया एक टिप्पणी छोड़ दें, मैं संपादित करूँगा।

यह उत्तर C ++ 03 पर लागू होता है। अन्य C ++ मानकों के लिए देखें:

समुच्चय क्या हैं और वे विशेष क्यों हैं

C ++ मानक से औपचारिक परिभाषा ( C ++ 03 8.5.1 : 1 ) :

कुल एक सरणी या एक वर्ग (खंड 9) है जिसमें कोई उपयोगकर्ता-घोषित निर्माता (12.1), कोई निजी या संरक्षित गैर-स्थैतिक डेटा सदस्य (खंड 11), कोई आधार वर्ग (खंड 10) और कोई आभासी कार्य नहीं है (10.3) )।

तो, ठीक है, चलो इस परिभाषा को पार्स करते हैं। सबसे पहले, कोई भी सरणी एक समुच्चय है। एक वर्ग भी हो सकता है अगर ... रुको! संरचनाओं या यूनियनों के बारे में कुछ नहीं कहा गया है, क्या वे समुच्चय नहीं हो सकते हैं? हा वो कर सकते है। सी ++ में, शब्द classसभी वर्गों, संरचनाओं और यूनियनों को संदर्भित करता है। तो, एक वर्ग (या संरचना, या संघ) एक समुच्चय है यदि और केवल अगर यह उपरोक्त परिभाषाओं से मानदंडों को पूरा करता है। इन मानदंडों का क्या मतलब है?

  • इसका मतलब यह नहीं है कि एक समग्र वर्ग में कंस्ट्रक्टर नहीं हो सकते हैं, वास्तव में यह एक डिफ़ॉल्ट कंस्ट्रक्टर और / या कॉपी कंस्ट्रक्टर हो सकता है जब तक कि वे संकलक द्वारा स्पष्ट रूप से घोषित किए जाते हैं, और उपयोगकर्ता द्वारा स्पष्ट रूप से नहीं।

  • कोई भी निजी या संरक्षित गैर-स्थैतिक डेटा सदस्य नहीं । आपके पास उतने निजी और संरक्षित सदस्य फ़ंक्शंस हो सकते हैं (लेकिन कंस्ट्रक्टर नहीं) और साथ ही कई निजी या संरक्षित स्टैटिक डेटा सदस्य और सदस्य फ़ंक्शंस जो आपको पसंद हैं और कुल वर्गों के नियमों का उल्लंघन नहीं करते हैं

  • एक समग्र वर्ग में एक उपयोगकर्ता-घोषित / उपयोगकर्ता-परिभाषित कॉपी-असाइनमेंट ऑपरेटर और / या विध्वंसक हो सकता है

  • एक सरणी एक समुच्चय है भले ही वह गैर-समुच्चय वर्ग प्रकार की एक सरणी हो।

अब कुछ उदाहरण देखते हैं:

class NotAggregate1
{
  virtual void f() {} //remember? no virtual functions
};

class NotAggregate2
{
  int x; //x is private by default and non-static 
};

class NotAggregate3
{
public:
  NotAggregate3(int) {} //oops, user-defined constructor
};

class Aggregate1
{
public:
  NotAggregate1 member1;   //ok, public member
  Aggregate1& operator=(Aggregate1 const & rhs) {/* */} //ok, copy-assignment  
private:
  void f() {} // ok, just a private function
};

तुम्हें नया तरीका मिल गया है। अब देखते हैं कि समुच्चय कैसे विशेष होते हैं। वे, गैर-कुल वर्गों के विपरीत, घुंघराले ब्रेसिज़ के साथ आरंभीकृत किए जा सकते हैं {}। यह इनिशियलाइज़ेशन सिंटैक्स सामान्यतः सरणियों के लिए जाना जाता है, और हमने अभी सीखा कि ये एग्रीगेट हैं। तो, चलो उनके साथ शुरू करते हैं।

Type array_name[n] = {a1, a2, …, am};

यदि (m == n) सरणी
के i वें तत्व को i के साथ आरंभीकृत किया जाता
है यदि (m <n)
सरणी के पहले m तत्व 1 , 2 , ..., m और अन्यn - mतत्वों केसाथ आरंभीकृतहोते हैं। यदि संभव हो तो, मूल्य-आरंभीकृत (शब्द की व्याख्या के लिए नीचे देखें)
और यदि (एम> एन)
कंपाइलर एक
और त्रुटि जारी करेगा (यह ऐसा मामला है जब एन बिल्कुल भी निर्दिष्ट नहीं है int a[] = {1, 2, 3};)
का आकार सरणी (n) को m के बराबर माना जाता है, इसलिएint a[] = {1, 2, 3};इसके बराबर हैint a[3] = {1, 2, 3};

जब अदिश प्रकार (की एक वस्तु bool, int, char, double, संकेत, आदि) है मूल्य प्रारंभ इसका मतलब है कि इसके साथ आरंभ नहीं हो जाता 0कि प्रकार के लिए ( falseके लिए bool, 0.0के लिए doubleआदि)। जब उपयोगकर्ता घोषित डिफॉल्ट कंस्ट्रक्टर के साथ वर्ग प्रकार का ऑब्जेक्ट वैल्यू-इनिशियलाइज्ड होता है तो उसका डिफॉल्ट कंस्ट्रक्टर कहलाता है। यदि डिफॉल्ट कंस्ट्रक्टर को स्पष्ट रूप से परिभाषित किया जाता है, तो सभी नॉनस्टैटिक सदस्यों की पुनरावृत्ति मूल्य-आरंभिक होती है। यह परिभाषा अभेद्य और थोड़ी गलत है, लेकिन यह आपको मूल विचार देना चाहिए। एक संदर्भ को मूल्य-आरंभ नहीं किया जा सकता है। गैर-एग्रीगेट वर्ग के लिए मान-आरंभीकरण विफल हो सकता है, उदाहरण के लिए, क्लास में कोई उपयुक्त डिफ़ॉल्ट कंस्ट्रक्टर नहीं है।

सरणी आरंभीकरण के उदाहरण:

class A
{
public:
  A(int) {} //no default constructor
};
class B
{
public:
  B() {} //default constructor available
};
int main()
{
  A a1[3] = {A(2), A(1), A(14)}; //OK n == m
  A a2[3] = {A(2)}; //ERROR A has no default constructor. Unable to value-initialize a2[1] and a2[2]
  B b1[3] = {B()}; //OK b1[1] and b1[2] are value initialized, in this case with the default-ctor
  int Array1[1000] = {0}; //All elements are initialized with 0;
  int Array2[1000] = {1}; //Attention: only the first element is 1, the rest are 0;
  bool Array3[1000] = {}; //the braces can be empty too. All elements initialized with false
  int Array4[1000]; //no initializer. This is different from an empty {} initializer in that
  //the elements in this case are not value-initialized, but have indeterminate values 
  //(unless, of course, Array4 is a global array)
  int array[2] = {1, 2, 3, 4}; //ERROR, too many initializers
}

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

struct X
{
  int i1;
  int i2;
};
struct Y
{
  char c;
  X x;
  int i[2];
  float f; 
protected:
  static double d;
private:
  void g(){}      
}; 

Y y = {'a', {10, 20}, {20, 30}};

ऊपर के उदाहरण में y.cसाथ आरंभ नहीं हो जाता 'a', y.x.i1साथ 10, y.x.i2साथ 20, y.i[0]साथ 20, y.i[1]साथ 30और y.fमूल्य-प्रारंभ, है कि, के साथ प्रारंभ है 0.0। संरक्षित स्थैतिक सदस्य dको आरंभिक नहीं किया जाता है, क्योंकि यह है static

अलग-अलग यूनियन इस मायने में अलग हैं कि आप केवल अपने पहले सदस्य को ब्रेसिज़ के साथ शुरू कर सकते हैं। मुझे लगता है कि यदि आप यूनियनों का उपयोग करने पर विचार करने के लिए सी ++ में पर्याप्त उन्नत हैं (उनका उपयोग बहुत खतरनाक हो सकता है और ध्यान से सोचा जाना चाहिए), तो आप मानक में यूनियनों के नियमों को देख सकते हैं :)।

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

इतना समुच्चय के बारे में पर्याप्त है। अब हम टाइप करने के लिए, PODs के कड़े सेट को परिभाषित कर सकते हैं

POD क्या हैं और वे विशेष क्यों हैं

C ++ मानक से औपचारिक परिभाषा ( C ++ 03 9 ) 4 ) :

POD- संरचना एक समग्र वर्ग है जिसमें गैर-POD- संरचना, गैर-POD- संघ (या इस प्रकार के सरणी) या संदर्भ के कोई भी गैर-स्थैतिक डेटा सदस्य नहीं होते हैं, और कोई उपयोगकर्ता-निर्धारित प्रतिलिपि असाइनमेंट ऑपरेटर और नहीं है उपयोगकर्ता-परिभाषित विध्वंसक। इसी तरह, एक POD- संघ एक समग्र संघ है जिसमें गैर-POD- संरचना, गैर POD- संघ (या इस प्रकार के सरणी) या संदर्भ के प्रकार के कोई गैर-स्थैतिक डेटा सदस्य नहीं होते हैं, और कोई उपयोगकर्ता-निर्धारित प्रतिलिपि असाइनमेंट ऑपरेटर नहीं होता है और कोई उपयोगकर्ता-परिभाषित विध्वंसक नहीं है। एक POD वर्ग एक ऐसा वर्ग है जो या तो POD- संरचना या POD- संघ है।

वाह, यह तोते के लिए मुश्किल है, है ना? :) आइए यूनियनों को बाहर छोड़ दें (ऊपर के रूप में उसी आधार पर) और थोड़ा स्पष्ट तरीके से रीफ़्रेज़ करें:

कुल वर्ग को POD कहा जाता है, यदि इसमें कोई उपयोगकर्ता-परिभाषित प्रतिलिपि-असाइनमेंट ऑपरेटर और विध्वंसक नहीं है और इसका कोई भी गैर-सदस्य सदस्य गैर-POD वर्ग, गैर-POD का सरणी या संदर्भ नहीं है।

इस परिभाषा का क्या अर्थ है? (क्या मैंने उल्लेख किया कि POD का मतलब प्लेन ओल्ड डेटा है ?)

  • सभी POD क्लासेस एग्रीगेट हैं, या, इसे दूसरे तरीके से रखने के लिए, यदि कोई क्लास एग्रीगेट नहीं है, तो यह निश्चित है कि POD नहीं है
  • कक्षाएं, केवल संरचनाओं की तरह, भले ही दोनों ही मामलों के लिए मानक शब्द POD- संरचना हो, लेकिन POD हो सकते हैं
  • जैसे समुच्चय के मामले में, इससे कोई फर्क नहीं पड़ता कि वर्ग के पास स्थिर सदस्य क्या हैं

उदाहरण:

struct POD
{
  int x;
  char y;
  void f() {} //no harm if there's a function
  static std::vector<char> v; //static members do not matter
};

struct AggregateButNotPOD1
{
  int x;
  ~AggregateButNotPOD1() {} //user-defined destructor
};

struct AggregateButNotPOD2
{
  AggregateButNotPOD1 arrOfNonPod[3]; //array of non-POD class
};

POD- क्लासेस, POD-unions, scalar types और इस तरह के सरणियों को सामूहिक रूप से POD- प्रकार कहा जाता है
POD कई मायनों में खास हैं। मैं सिर्फ कुछ उदाहरण प्रदान करता हूँ।

  • POD- क्लास C स्ट्रक्चर्स के सबसे करीब हैं। उनके विपरीत, पीओडी में सदस्य कार्य और मनमाने ढंग से स्थिर सदस्य हो सकते हैं, लेकिन इन दोनों में से कोई भी वस्तु का मेमोरी लेआउट नहीं बदलता है। इसलिए यदि आप अधिक या कम पोर्टेबल डायनेमिक लाइब्रेरी लिखना चाहते हैं जिसका उपयोग C और यहां तक ​​कि .NET से किया जा सकता है, तो आपको अपने सभी निर्यात किए गए कार्यों को लेने और POD- प्रकार के केवल मापदंडों को वापस करने की कोशिश करनी चाहिए।

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

  • POD प्रकारों की वस्तुओं के लिए यह मानक द्वारा गारंटी दी जाती है कि जब आप memcpyअपनी वस्तु की सामग्री को चार या असेंबली चार की श्रेणी में रखते हैं, और फिर memcpyसामग्री वापस आपकी वस्तु में आ जाती है, तो वस्तु अपने मूल मूल्य को धारण करेगी। ध्यान दें कि गैर-पीओडी प्रकारों की वस्तुओं के लिए ऐसी कोई गारंटी नहीं है। इसके अलावा, आप सुरक्षित रूप से POD ऑब्जेक्ट्स की प्रतिलिपि बना सकते हैं memcpy। निम्नलिखित उदाहरण मानता है कि T एक POD- प्रकार है:

    #define N sizeof(T)
    char buf[N];
    T obj; // obj initialized to its original value
    memcpy(buf, &obj, N); // between these two calls to memcpy,
    // obj might be modified
    memcpy(&obj, buf, N); // at this point, each subobject of obj of scalar type
    // holds its original value
  • गोटो बयान। जैसा कि आप जानते हैं, यह गैरकानूनी है (कंपाइलर को एक त्रुटि जारी करनी चाहिए) एक बिंदु से गोटो के माध्यम से एक छलांग लगाने के लिए जहां कुछ चर अभी तक एक बिंदु के दायरे में नहीं था जहां यह पहले से ही गुंजाइश है। यह प्रतिबंध केवल तभी लागू होता है जब चर गैर-पीओडी प्रकार का होता है। निम्नलिखित उदाहरण f()में बीमार है, जबकि g()अच्छी तरह से गठित है। ध्यान दें कि Microsoft का कंपाइलर इस नियम से बहुत उदार है - यह दोनों मामलों में एक चेतावनी जारी करता है।

    int f()
    {
      struct NonPOD {NonPOD() {}};
      goto label;
      NonPOD x;
    label:
      return 0;
    }
    
    int g()
    {
      struct POD {int i; char c;};
      goto label;
      POD x;
    label:
      return 0;
    }
  • यह गारंटी है कि एक POD ऑब्जेक्ट की शुरुआत में कोई पैडिंग नहीं होगी। दूसरे शब्दों में, अगर एक पॉड स्तरीय एक का पहला सदस्य प्रकार टी की है, तो आप सुरक्षित रूप से कर सकते हैं reinterpret_castसे A*करने के लिए T*और सूचक प्राप्त पहले सदस्य और इसके विपरीत।

यह सूची लम्बी होते चली जाती है…

निष्कर्ष

यह समझना महत्वपूर्ण है कि वास्तव में एक POD क्या है क्योंकि कई भाषा सुविधाएँ, जैसा कि आप देखते हैं, उनके लिए अलग तरह से व्यवहार करते हैं।


3
अच्छा उत्तर। टिप्पणियाँ: "यदि डिफ़ॉल्ट कंस्ट्रक्टर को स्पष्ट रूप से परिभाषित किया गया है, तो सभी नॉनस्टैटिक सदस्यों का पुनरावर्ती मूल्य-आरंभ किया जाता है।" और "गैर-एग्रीगेट वर्ग के लिए मूल्य-प्रारंभकरण विफल हो सकता है, उदाहरण के लिए, क्लास में कोई उपयुक्त डिफ़ॉल्ट कंस्ट्रक्टर नहीं है।" यह सही नहीं है: एक अंतर्निहित- घोषित डिफ़ॉल्ट निर्माता के साथ एक वर्ग के मूल्य का आरंभीकरण एक अंतर्निहित-परिभाषित डिफ़ॉल्ट डिफेंडर की आवश्यकता नहीं है। इस प्रकार, दिया ( private:उपयुक्त के रूप में सम्मिलित करें): struct A { int const a; };तो A()अच्छी तरह से गठित है, भले ही Aडिफ़ॉल्ट रचनाकार परिभाषा बीमार हो।
जोहान्स शाउब -

4
@Kev: यदि आप एक ही जानकारी को एक छोटे से उत्तर में पैक करने का प्रबंधन करते हैं, तो हम सभी को खुशी से वोट देंगे!
sbi

3
@Armen आप भी एक ही सवाल के कई जवाब कर सकते हैं ध्यान दें। प्रत्येक उत्तर में प्रश्न के हल का हिस्सा हो सकता है। पेंच कि स्वीकृत-चिह्न वाली बात, मेरी राय में :)
जोहान्स शाउब - 17:14

3
उत्तर बहुत अच्छा है। मैं अभी भी कुछ समय के लिए इस पोस्ट को पुनः देख रहा हूँ। वैसे विजुअल स्टूडियो के लिए चेतावनी के बारे में। फली के लिए "गोटो स्टेटमेंट" MSVC संकलक के लिए अज्ञानता के साथ आता है जैसा कि आपने उल्लेख किया है। लेकिन स्विच / केस स्टेटमेंट के लिए यह संकलन त्रुटि उत्पन्न करता है। इस अवधारणा के आधार पर मैंने कुछ टेस्ट-पॉड-चेकर
बनाये हैं

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

457

C ++ 11 के लिए क्या परिवर्तन हैं?

समुच्चय

एक समुच्चय की मानक परिभाषा थोड़ी बदल गई है, लेकिन यह अभी भी बहुत समान है:

कुल एक सरणी या एक वर्ग (क्लाज 9) है जिसमें कोई उपयोगकर्ता-प्रदान किए गए निर्माता (12.1), गैर-स्थैतिक डेटा सदस्यों (9.2) के लिए कोई ब्रेस-या-इक्वलाइज़र नहीं है (9.2), कोई निजी या संरक्षित गैर-स्थैतिक डेटा सदस्य (नहीं) क्लाज 11), कोई बेस क्लास (क्लाज 10), और कोई वर्चुअल फंक्शन (10.3) नहीं।

ठीक है, क्या बदल गया?

  1. पहले, कुल में कोई उपयोगकर्ता-घोषित निर्माता नहीं हो सकता था, लेकिन अब इसमें उपयोगकर्ता-प्रदान किए गए निर्माता नहीं हो सकते । क्या कोई अंतर है? हाँ, वहाँ है, क्योंकि अब आप निर्माणकर्ताओं की घोषणा कर सकते हैं और उन्हें डिफ़ॉल्ट कर सकते हैं:

    struct Aggregate {
        Aggregate() = default; // asks the compiler to generate the default implementation
    };

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

  2. अब कुल मिलाकर कोई नहीं हो सकता है गैर-स्थैतिक डेटा सदस्यों के लिए ब्रेस-या-इक्वलाइज़र । इसका क्या मतलब है? खैर, यह सिर्फ इसलिए है क्योंकि इस नए मानक के साथ, हम सदस्यों को इस तरह सीधे कक्षा में आरंभीकृत कर सकते हैं:

    struct NotAggregate {
        int x = 5; // valid in C++11
        std::vector<int> s{1,2,3}; // also valid
    };

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

तो, क्या एक कुल मिलाकर बहुत कुछ नहीं बदला है। यह अभी भी एक ही मूल विचार है, नई सुविधाओं के लिए अनुकूलित।

PODs के बारे में क्या?

POD बहुत सारे परिवर्तनों से गुजरे। POD के बारे में पिछले नियमों के बहुत सारे इस नए मानक में ढील दी गई थी, और मानक में प्रदान की जाने वाली परिभाषा को मौलिक रूप से बदल दिया गया था।

एक पीओडी का विचार मूल रूप से दो अलग-अलग गुणों पर कब्जा करना है:

  1. यह स्थैतिक आरंभ का समर्थन करता है, और
  2. C ++ में POD संकलित करना आपको C में संकलित संरचना के समान मेमोरी लेआउट देता है।

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

नई परिभाषा मूल रूप से कहती है कि एक पीओडी एक ऐसा वर्ग है जो दोनों तुच्छ है और मानक-लेआउट है, और इस संपत्ति को सभी गैर-स्थैतिक डेटा सदस्यों के लिए पुनरावर्ती होना चाहिए:

POD संरचना एक गैर-संघी वर्ग है जो एक तुच्छ वर्ग और मानक-लेआउट वर्ग दोनों है, और इसमें गैर-POD संरचना, गैर-पीओडी संघ (या इस प्रकार के सरणी) के गैर-स्थैतिक डेटा सदस्य नहीं हैं। इसी तरह, एक पीओडी यूनियन एक संघ है जो एक तुच्छ वर्ग और मानक लेआउट वर्ग दोनों है, और इसमें गैर-पीओडी संरचना, गैर-पीओडी संघ (या इस प्रकार के सरणी) के गैर-स्थैतिक डेटा सदस्य नहीं हैं। POD वर्ग एक ऐसा वर्ग है जो या तो POD संरचना या POD संघ है।

आइए इन दोनों गुणों में से प्रत्येक पर अलग से विस्तार से जाएं।

तुच्छ वर्ग

ट्रिवियल ऊपर बताई गई पहली संपत्ति है: तुच्छ वर्ग स्थैतिक आरंभ का समर्थन करते हैं। यदि कोई वर्ग तुच्छ रूप से कॉपी करने योग्य (तुच्छ वर्गों का सुपरसेट) है, तो उस स्थान पर अपने प्रतिनिधित्व को चीजों की तरह से कॉपी करना ठीक है memcpyऔर परिणाम समान होने की उम्मीद करना।

मानक एक तुच्छ वर्ग को निम्नानुसार परिभाषित करता है:

एक तुच्छ कॉपी करने वाला वर्ग एक वर्ग है जो:

- कोई गैर-तुच्छ कॉपी निर्माता नहीं है (12.8),

- कोई गैर-तुच्छ चाल निर्माण नहीं है (12.8),

- कोई गैर-तुच्छ कॉपी असाइनमेंट ऑपरेटर नहीं है (13.5.3, 12.8),

- कोई गैर-तुच्छ चाल असाइनमेंट ऑपरेटर (13.5.3, 12.8) और नहीं है

- एक तुच्छ विध्वंसक (12.4) है।

एक तुच्छ वर्ग एक वर्ग है जिसमें एक तुच्छ डिफ़ॉल्ट रचनाकार (12.1) है और तुच्छ रूप से प्रतिलिपि योग्य है।

[ नोट: विशेष रूप से, एक तुच्छ प्रतिलिपि या तुच्छ वर्ग में वर्चुअल फ़ंक्शंस या वर्चुअल बेस कक्षाएं नहीं होती हैं। ध्यान दें ]

तो, उन सभी तुच्छ और गैर-तुच्छ चीजें क्या हैं?

कक्षा X के लिए एक कॉपी / मूव कंस्ट्रक्टर तुच्छ है यदि यह उपयोगकर्ता द्वारा प्रदान नहीं किया गया है और यदि है

- कक्षा X में कोई वर्चुअल फ़ंक्शंस (10.3) और कोई वर्चुअल बेस क्लास (10.1) और नहीं है

- प्रत्येक डायरेक्ट बेस क्लास सबोबिज को कॉपी / ले जाने के लिए चयनित कंस्ट्रक्टर तुच्छ है, और

- एक्स के प्रत्येक गैर-स्थैतिक डेटा सदस्य के लिए जो वर्ग प्रकार (या उसके प्रकार) का है, उस सदस्य को उस सदस्य को कॉपी / स्थानांतरित करने के लिए चयनित निर्माता है जो तुच्छ है;

अन्यथा कॉपी / मूव कंस्ट्रक्टर गैर-तुच्छ है।

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

एक तुच्छ प्रतिलिपि / चाल असाइनमेंट ऑपरेटर की परिभाषा बहुत समान है, बस "निर्माता" शब्द को "असाइनमेंट ऑपरेटर" के साथ बदल दिया जाता है।

एक तुच्छ विध्वंसक की भी इसी तरह की परिभाषा है, अतिरिक्त बाधा के साथ कि यह आभासी नहीं हो सकता है।

और फिर भी एक और समान नियम तुच्छ डिफ़ॉल्ट निर्माणकर्ताओं के लिए मौजूद है, इसके साथ ही यदि कोई डिफ़ॉल्ट कंस्ट्रक्टर तुच्छ नहीं है, यदि वर्ग में गैर-स्थैतिक डेटा सदस्य हैं जो ब्रेस-या-समान-इनिशियलाइज़र्स के साथ हैं , जिसे हमने ऊपर देखा है।

यहाँ सब कुछ स्पष्ट करने के लिए कुछ उदाहरण दिए गए हैं:

// empty classes are trivial
struct Trivial1 {};

// all special members are implicit
struct Trivial2 {
    int x;
};

struct Trivial3 : Trivial2 { // base class is trivial
    Trivial3() = default; // not a user-provided ctor
    int y;
};

struct Trivial4 {
public:
    int a;
private: // no restrictions on access modifiers
    int b;
};

struct Trivial5 {
    Trivial1 a;
    Trivial2 b;
    Trivial3 c;
    Trivial4 d;
};

struct Trivial6 {
    Trivial2 a[23];
};

struct Trivial7 {
    Trivial6 c;
    void f(); // it's okay to have non-virtual functions
};

struct Trivial8 {
     int x;
     static NonTrivial1 y; // no restrictions on static members
};

struct Trivial9 {
     Trivial9() = default; // not user-provided
      // a regular constructor is okay because we still have default ctor
     Trivial9(int x) : x(x) {};
     int x;
};

struct NonTrivial1 : Trivial3 {
    virtual void f(); // virtual members make non-trivial ctors
};

struct NonTrivial2 {
    NonTrivial2() : z(42) {} // user-provided ctor
    int z;
};

struct NonTrivial3 {
    NonTrivial3(); // user-provided ctor
    int w;
};
NonTrivial3::NonTrivial3() = default; // defaulted but not on first declaration
                                      // still counts as user-provided
struct NonTrivial5 {
    virtual ~NonTrivial5(); // virtual destructors are not trivial
};

मानक लेआउट

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

यह एक और संपत्ति है जो सदस्यों और सभी आधार वर्गों के लिए पुनरावर्ती होनी चाहिए। और हमेशा की तरह, कोई वर्चुअल फ़ंक्शंस या वर्चुअल बेस क्लास की अनुमति नहीं है। यह लेआउट को C के साथ असंगत बना देगा।

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

वंशानुक्रम का उपयोग करते समय, पूरे वंशानुक्रम में केवल एक वर्ग में गैर-स्थैतिक डेटा सदस्य हो सकते हैं, और पहला गैर-स्थैतिक डेटा सदस्य बेस क्लास प्रकार का नहीं हो सकता है (यह नियमों का उल्लंघन कर सकता है), अन्यथा, यह एक मानक नहीं है- लेआउट वर्ग।

मानक पाठ में परिभाषा इस प्रकार है:

एक मानक-लेआउट वर्ग एक वर्ग है जो:

- गैर-मानक-लेआउट वर्ग (या इस प्रकार के सरणी) या संदर्भ के प्रकार का कोई गैर-स्थैतिक डेटा सदस्य नहीं है,

- कोई आभासी कार्य नहीं है (10.3) और कोई आभासी आधार कक्षाएं (10.1),

- सभी गैर-स्थैतिक डेटा सदस्यों के लिए समान अभिगम नियंत्रण (क्लाज 11) है,

- कोई गैर-मानक-लेआउट आधार वर्ग नहीं है,

- या तो सबसे व्युत्पन्न वर्ग में कोई गैर-स्थैतिक डेटा सदस्य नहीं है और गैर-स्थैतिक डेटा सदस्यों के साथ सबसे अधिक बेस क्लास है, या गैर-स्थैतिक डेटा सदस्यों के साथ कोई आधार वर्ग नहीं है, और

- पहले गैर-स्थैतिक डेटा सदस्य के समान प्रकार का कोई आधार वर्ग नहीं है।

एक मानक-लेआउट संरचना एक मानक-लेआउट वर्ग है जिसे कक्षा-कुंजी संरचना या वर्ग-कुंजी वर्ग के साथ परिभाषित किया गया है।

एक मानक-लेआउट संघ एक मानक-लेआउट वर्ग है जिसे क्लास-की यूनियन के साथ परिभाषित किया गया है।

[ नोट: मानक-लेआउट कक्षाएं अन्य प्रोग्रामिंग भाषाओं में लिखे गए कोड के साथ संवाद करने के लिए उपयोगी हैं। उनका लेआउट 9.2 में निर्दिष्ट है। ध्यान दें ]

और आइए कुछ उदाहरण देखें।

// empty classes have standard-layout
struct StandardLayout1 {};

struct StandardLayout2 {
    int x;
};

struct StandardLayout3 {
private: // both are private, so it's ok
    int x;
    int y;
};

struct StandardLayout4 : StandardLayout1 {
    int x;
    int y;

    void f(); // perfectly fine to have non-virtual functions
};

struct StandardLayout5 : StandardLayout1 {
    int x;
    StandardLayout1 y; // can have members of base type if they're not the first
};

struct StandardLayout6 : StandardLayout1, StandardLayout5 {
    // can use multiple inheritance as long only
    // one class in the hierarchy has non-static data members
};

struct StandardLayout7 {
    int x;
    int y;
    StandardLayout7(int x, int y) : x(x), y(y) {} // user-provided ctors are ok
};

struct StandardLayout8 {
public:
    StandardLayout8(int x) : x(x) {} // user-provided ctors are ok
// ok to have non-static data members and other members with different access
private:
    int x;
};

struct StandardLayout9 {
    int x;
    static NonStandardLayout1 y; // no restrictions on static members
};

struct NonStandardLayout1 {
    virtual f(); // cannot have virtual functions
};

struct NonStandardLayout2 {
    NonStandardLayout1 X; // has non-standard-layout member
};

struct NonStandardLayout3 : StandardLayout1 {
    StandardLayout1 x; // first member cannot be of the same type as base
};

struct NonStandardLayout4 : StandardLayout3 {
    int z; // more than one class has non-static data members
};

struct NonStandardLayout5 : NonStandardLayout3 {}; // has a non-standard-layout base class

निष्कर्ष

इन नए नियमों के साथ बहुत अधिक प्रकार अब POD हो सकते हैं। और यहां तक ​​कि अगर एक प्रकार POD नहीं है, तो हम कुछ POD गुणों का अलग से लाभ उठा सकते हैं (यदि यह केवल तुच्छ या मानक-लेआउट में से एक है)।

मानक लाइब्रेरी में शीर्ष लेख में इन गुणों का परीक्षण करने का गुण है <type_traits>:

template <typename T>
struct std::is_pod;
template <typename T>
struct std::is_trivial;
template <typename T>
struct std::is_trivially_copyable;
template <typename T>
struct std::is_standard_layout;

2
क्या आप निम्नलिखित नियमों को विस्तृत कर सकते हैं: क) मानक-लेआउट कक्षाओं में सभी गैर-स्थैतिक डेटा सदस्यों को एक ही अभिगम नियंत्रण के साथ होना चाहिए; ख) पूरे वंशानुक्रम में केवल एक वर्ग में गैर-स्थैतिक डेटा सदस्य हो सकते हैं, और पहला गैर-स्थैतिक डेटा सदस्य बेस क्लास प्रकार का नहीं हो सकता (यह नियमों को तोड़ सकता है)। विशेष रूप से उनके लिए क्या कारण हैं? बाद के नियम के लिए, क्या आप अलियासिंग को तोड़ने का एक उदाहरण प्रदान कर सकते हैं?
एंड्री टाइलिचको

@AndyT: मेरा जवाब देखें। मैंने अपने ज्ञान का सबसे अच्छा जवाब देने की कोशिश की।
निकोल बोलस

5
C ++ 14 के लिए इसे अपडेट करना चाह सकते हैं, जिसने समुच्चय के लिए "कोई ब्रेस-या-इक्विल-इनिशियलाइज़र" आवश्यकता को हटा दिया।
TC

@ शीर्ष-अप के लिए धन्यवाद। मैं जल्द ही उन परिवर्तनों को देखूंगा और इसे अपडेट करूंगा।
आर। मार्टिनो फर्नांडिस

1
अलियासिंग के बारे में: एक C ++ लेआउट नियम है कि यदि एक वर्ग C में (खाली) आधार X है, और C का पहला डेटा सदस्य X है, तो वह पहला सदस्य आधार X के समान ऑफसेट पर नहीं हो सकता है; इससे बचने के लिए जरूरत पड़ने पर इसके आगे डमी पैडिंग बाइट मिलती है। एक ही पते पर X (या उपवर्ग) के दो उदाहरण होने से उन चीजों को तोड़ सकते हैं जिन्हें अलग-अलग उदाहरणों को अपने पते के माध्यम से अलग करने की आवश्यकता होती है (एक खाली उदाहरण के पास इसे अलग करने के लिए और कुछ नहीं है ...)। किसी भी स्थिति में उस पैडिंग बाइट को 'लेआउट कम्पेटिबल' में रखने की आवश्यकता है।
ग्राग्गो

106

C ++ 14 के लिए क्या बदल गया है

हम संदर्भ के लिए ड्राफ्ट C ++ 14 मानक का उल्लेख कर सकते हैं ।

समुच्चय

यह खंड 8.5.1 एग्रीगेट्स में शामिल है जो हमें निम्नलिखित परिभाषा देता है:

कुल एक सरणी या एक वर्ग (क्लाज 9) है, जिसमें कोई उपयोगकर्ता-प्रदान किए गए निर्माता (12.1), कोई निजी या संरक्षित गैर-स्थैतिक डेटा सदस्य (क्लाज 11), कोई आधार वर्ग (क्लाज 10) और कोई वर्चुअल फ़ंक्शन (10.3) नहीं है। )।

एकमात्र बदलाव अब इन-क्लास मेंबर इनिशियलाइज़र्स को जोड़ रहा है जो क्लास को नॉन-एग्रीगेट नहीं बनाता है। तो निम्न उदाहरणों में C + 11 एग्रीगेट इनिशियलाइज़ेशन फ़ॉर क्लासेस फॉर मेंबर इन-स्पीड इनिशियलाइज़र्स :

struct A
{
  int a = 3;
  int b = 3;
};

C ++ 11 में एक समुच्चय नहीं था लेकिन यह C ++ 14 में है। यह परिवर्तन N3605 में कवर किया गया है : सदस्य शुरुआती और समुच्चय , जिसमें निम्नलिखित सार हैं:

ब्रेज़न स्ट्रॉस्ट्रुप और रिचर्ड स्मिथ ने कुल मिलाकर प्रारंभिक और सदस्य-आरंभीकरण के बारे में एक मुद्दा उठाया। इस पत्र में स्मिथ के प्रस्तावित शब्दों को अपनाने से समस्या को हल करने का प्रस्ताव है जो एक प्रतिबंध को हटाता है जो समुच्चय को सदस्य-आरम्भकर्ता नहीं कर सकता है।

POD वही रहता है

POD ( सादा पुराने डेटा ) संरचना के लिए परिभाषा अनुभाग 9 वर्गों में शामिल है जो कहता है:

एक POD संरचना 110 एक गैर-संघी वर्ग है जो एक तुच्छ वर्ग और मानक-लेआउट वर्ग दोनों है, और इसमें गैर-POD संरचना, गैर-पीओडी संघ (या इस प्रकार के सरणी) का कोई गैर-स्थैतिक डेटा सदस्य नहीं है। इसी तरह, एक पीओडी यूनियन एक संघ है जो एक तुच्छ वर्ग और मानक-लेआउट वर्ग दोनों है, और इसमें गैर-पीओडी संरचना, गैर-पीओडी संघ (या इस प्रकार के सरणी) प्रकार के गैर-स्थैतिक डेटा सदस्य नहीं हैं। POD वर्ग एक ऐसा वर्ग है जो या तो POD संरचना या POD संघ है।

जो C ++ 11 जैसा ही शब्द है।

C ++ 14 के लिए मानक-लेआउट परिवर्तन

जैसा कि टिप्पणियों में उल्लेख किया गया है कि फली मानक-लेआउट की परिभाषा पर निर्भर करती है और यह C ++ 14 के लिए बदल गई थी लेकिन यह दोष रिपोर्ट के माध्यम से था जो तथ्य के बाद C ++ 14 पर लागू किया गया था।

तीन डीआर थे:

इसलिए मानक-लेआउट इस प्री C ++ 14 से चला गया:

एक मानक-लेआउट वर्ग एक वर्ग है जो:

  • (7.1) में गैर-मानक-लेआउट वर्ग (या इस प्रकार के सरणी) या संदर्भ के गैर-स्थैतिक डेटा सदस्य नहीं हैं,)
  • (7.2) का कोई आभासी कार्य नहीं है ([class.virtual]) और कोई आभासी आधार कक्षाएं ([class.mi]),
  • (7.3) सभी गैर-स्थैतिक डेटा सदस्यों के लिए एक ही अभिगम नियंत्रण (क्लाज [class.access]) है,
  • (7.4) में कोई गैर-मानक-लेआउट बेस क्लास नहीं है,
  • ((.५) या तो सबसे व्युत्पन्न वर्ग में कोई गैर-स्थैतिक डेटा सदस्य नहीं है और गैर-स्थैतिक डेटा सदस्यों के साथ सबसे अधिक बेस क्लास है, या गैर-स्थैतिक डेटा सदस्यों के साथ कोई आधार वर्ग नहीं है, और
  • ((.६) में पहले गैर-स्थैतिक डेटा सदस्य के रूप में एक ही प्रकार का कोई आधार वर्ग नहीं है। १० ९

करने के लिए सी ++ 14 में इस :

एक वर्ग S एक मानक-लेआउट वर्ग है यदि वह:

  • (3.1) में गैर-मानक-लेआउट वर्ग (या इस प्रकार के सरणी) या संदर्भ प्रकार के गैर-स्थैतिक डेटा सदस्य नहीं हैं,)
  • (3.2) में कोई वर्चुअल फ़ंक्शंस नहीं है और कोई वर्चुअल बेस क्लास नहीं है,
  • (3.3) सभी गैर-स्थैतिक डेटा सदस्यों के लिए समान अभिगम नियंत्रण है,
  • (३.४) कोई गैर-मानक-लेआउट आधार वर्ग नहीं है,
  • (३.५) में किसी भी प्रकार के अधिकांश एक बेस क्लास सब -जेक्ट हैं,
  • (३.६) वर्ग में सभी गैर-स्थैतिक डेटा सदस्य और बिट-फ़ील्ड हैं और इसके आधार वर्ग को पहले एक ही कक्षा में घोषित किया गया है, और
  • (3.7) में बेस क्लास के रूप में प्रकारों के सेट M (S) का कोई तत्व नहीं है, जहां किसी भी प्रकार के लिए X, M (X) को अनुसरण के रूप में परिभाषित किया गया है। [नोट: M (X) प्रकार के प्रकार का सेट है सभी गैर-बेस-क्लास उप-विषय जो कि X- अंत नोट में शून्य ऑफसेट पर हो सकते हैं]
    • (3.7.1) यदि X एक गैर-संघी वर्ग प्रकार है जिसमें बिना (संभवतः विरासत में) गैर-स्थैतिक डेटा सदस्य हैं, तो M (X) सेट खाली है।
    • (3.7.2) यदि X एक गैर-संघी वर्ग प्रकार है, जिसमें X0 का गैर-स्थिर डेटा सदस्य है, जो या तो शून्य आकार का है या X का पहला गैर-स्थैतिक डेटा सदस्य है (जहां कहा गया सदस्य एक अनाम संघ हो सकता है ), सेट M (X) में X0 और M (X0) के तत्व होते हैं।
    • (3.7.3) यदि X एक यूनियन प्रकार है, तो सेट M (X) सभी M (Ui) का संघ है और सभी Ui युक्त सेट है, जहां प्रत्येक Ui X के ith गैर-स्थैतिक डेटा सदस्य का प्रकार है ।
    • (3.7.4) यदि X तत्व प्रकार Xe के साथ एक सरणी प्रकार है, तो सेट M (X) में Xe और M (Xe) के तत्व होते हैं।
    • (3.7.5) यदि X एक गैर-वर्ग, गैर-सरणी प्रकार है, तो M (X) सेट खाली है।

4
समुच्चय को आधार वर्ग रखने की अनुमति देने का एक प्रस्ताव है जब तक कि यह डिफ़ॉल्ट रूप से देखने योग्य
Shafik Yaghmour

जब POD वही रह सकता है, C ++ 14 StandardLayoutType, जो POD के लिए एक आवश्यकता है, cppref के अनुसार बदल गया है: en.cppreference.com/w/cpp/onym_req/StandardLayoutType
Ciro Santilli 冠状 the the 法轮功 法轮功

1
@CiroSantilli 新疆 改造 ill 事件,, धन्यवाद, मुझे नहीं पता कि मैं उन लोगों से कैसे चूक गया, मैं अगले कुछ दिनों में अपडेट करने की कोशिश करूंगा।
शफीक याघमोर

मुझे बताएं कि क्या आप एक उदाहरण के साथ आ सकते हैं जो C ++ 14 में POD है लेकिन C ++ 11 में नहीं है :-) मैंने उदाहरणों की एक विस्तृत सूची यहां शुरू की है: stackoverflow.com/questions/146452/what- हैं-पॉड-प्रकार-इन-सी /…
सिरो सेंटिल्ली 冠状---

1
@CiroSantilli 新疆 改造 六四 事件 法轮功 happened तो यहाँ क्या हुआ अगर हम C ++ 11 और C ++ 14 में मानक-लेआउट विवरण को देखें तो वे मेल खाते हैं। ये परिवर्तन जहां दोष रिपोर्ट के माध्यम से C ++ 14 पर वापस लागू होते हैं। इसलिए जब मैंने इसे लिखा था तो यह मूल रूप से सही था :-p
शफीक यघमौर

47

क्या आप निम्नलिखित नियमों को विस्तृत कर सकते हैं:

मै कोशिश करुॅगा:

क) मानक-लेआउट कक्षाओं में सभी गैर-स्थैतिक डेटा सदस्य एक ही अभिगम नियंत्रण के साथ होने चाहिए

यही कारण है कि सरल है: सभी गैर-स्थिर डेटा सदस्यों चाहिए सब हो public, privateया protected। आपके पास कुछ publicऔर कुछ नहीं हो सकता हैprivate

उनके लिए तर्क "मानक लेआउट" और "मानक लेआउट नहीं" के बीच अंतर होने के तर्क को जाता है। अर्थात्, संकलक को यह चुनने की स्वतंत्रता देने के लिए कि चीजों को स्मृति में कैसे रखा जाए। यह सिर्फ व्यवहार्य बिंदुओं के बारे में नहीं है।

जब उन्होंने 98 में C ++ को मानकीकृत किया, तो उन्हें मूल रूप से यह अनुमान लगाना था कि लोग इसे कैसे लागू करेंगे। हालांकि उन्हें C ++ के विभिन्न स्वादों के साथ कार्यान्वयन का काफी अनुभव था, वे चीजों के बारे में निश्चित नहीं थे। इसलिए उन्होंने सतर्क रहने का फैसला किया: कंपाइलरों को यथासंभव स्वतंत्रता दें।

इसलिए C ++ 98 में POD की परिभाषा इतनी सख्त है। इसने सी ++ को अधिकांश वर्गों के लिए सदस्य लेआउट पर बहुत अक्षांश दिया। असल में, POD प्रकारों को विशेष मामलों के लिए बनाया गया था, कुछ ऐसा जो आपने विशेष रूप से एक कारण के लिए लिखा था।

जब C ++ 11 पर काम किया जा रहा था, तो उन्हें संकलक के साथ बहुत अधिक अनुभव था। और उन्होंने महसूस किया कि ... सी ++ संकलक लेखक वास्तव में आलसी हैं। वे यह सब स्वतंत्रता था, लेकिन वे नहीं किया करते हैं इसके साथ कुछ भी।

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

अब, जब यह आया public/ private, चीजें अलग हैं। सदस्यों के लिए publicबनाम जो privateवास्तव में हैं, उन्हें फिर से संकलित करने की स्वतंत्रता , विशेष रूप से डिबगिंग बिल्ड में। और जब से मानक लेआउट का मुद्दा यह है कि अन्य भाषाओं के साथ संगतता है, तो आपके पास डिबग बनाम रिलीज़ में लेआउट अलग नहीं हो सकता है।

फिर यह तथ्य है कि यह वास्तव में उपयोगकर्ता को चोट नहीं पहुंचाता है। यदि आप एक अतिक्रमित वर्ग बना रहे हैं, तो संभावनाएँ अच्छी हैं कि आपके सभी डेटा सदस्य privateवैसे भी होंगे। आप आमतौर पर सार्वजनिक डेटा सदस्यों को पूरी तरह से समझाया प्रकारों पर उजागर नहीं करते हैं। तो यह केवल उन कुछ उपयोगकर्ताओं के लिए एक समस्या होगी जो ऐसा करना चाहते हैं, जो उस विभाजन को चाहते हैं।

इसलिए यह कोई बड़ी क्षति नहीं है।

बी) पूरे वंशानुक्रम में केवल एक वर्ग में गैर-स्थैतिक डेटा सदस्य हो सकते हैं,

इसका कारण यह है कि वे मानक लेआउट को फिर से मानकीकृत क्यों करते हैं: सामान्य अभ्यास।

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

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

आप वह सब कुछ नहीं कर सकते हैं जिसमें वर्चुअल फ़ंक्शंस और एक डिफ़ॉल्ट कंस्ट्रक्टर मानक लेआउट नहीं है।

और पहला गैर-स्थैतिक डेटा सदस्य आधार वर्ग प्रकार का नहीं हो सकता (यह नियमों को तोड़ सकता है)।

मैं वास्तव में इस एक से बात नहीं कर सकता। मैं पर्याप्त रूप से C ++ के नियमों का पालन करने के लिए शिक्षित नहीं हूं, इसे वास्तव में समझने के लिए। लेकिन इसका इस तथ्य के साथ कुछ लेना-देना है कि आधार सदस्य उसी पते को साझा करेगा, जो आधार वर्ग स्वयं करता है। अर्थात्:

struct Base {};
struct Derived : Base { Base b; };

Derived d;
static_cast<Base*>(&d) == &d.b;

और वह शायद C ++ के नियमों के विरुद्ध है। किसी तरह।

हालांकि, इस पर विचार करें: वास्तव में ऐसा करने की क्षमता कितनी उपयोगी हो सकती है? चूँकि केवल एक वर्ग में गैर-स्थैतिक डेटा सदस्य हो सकते हैं, तो Derivedवह वर्ग होना चाहिए (क्योंकि इसमें Baseसदस्य के रूप में)। तो खाली Base होना चाहिए (डेटा का)। और अगर Baseखाली है, साथ ही एक आधार वर्ग है ... तो इसका एक डेटा सदस्य क्यों है?

चूंकि Baseखाली है, इसकी कोई स्थिति नहीं है। इसलिए कोई भी गैर-स्थैतिक सदस्य फ़ंक्शन अपने मापदंडों के आधार पर वही करेगा जो वे अपने thisसंकेतक के आधार पर करते हैं ।

तो फिर से: कोई बड़ा नुकसान नहीं।


स्पष्टीकरण के लिए धन्यवाद, यह बहुत मदद करता है। संभवतः इसके बावजूद static_cast<Base*>(&d)और &d.bएक ही Base*प्रकार के हैं, वे अलग-अलग चीज़ों की ओर इशारा करते हैं और इस प्रकार अलियासिंग नियम को तोड़ते हैं। कृप्या मुझे सही करें।
एंड्री टाइक्लेको

1
और, यदि केवल एक वर्ग में गैर-स्थैतिक डेटा सदस्य हो सकते हैं, तो Derivedक्या वह वर्ग होना चाहिए?
एंड्री टाइक्लेको

3
@AndyT: इसके Derivedपहले सदस्य के लिए इसका आधार वर्ग होने के लिए, इसमें दो चीजें होनी चाहिए: एक आधार वर्ग, और एक सदस्य । और चूंकि पदानुक्रम में केवल एक वर्ग के सदस्य हो सकते हैं (और अभी भी मानक-लेआउट हो सकते हैं), इसका मतलब है कि इसके आधार वर्ग में सदस्य नहीं हो सकते।
निकोल बोलस

3
@AndyT, हाँ, आप अनिवार्य रूप से सही हैं, IME, अलियासिंग नियम के बारे में। एक ही प्रकार के दो अलग-अलग उदाहरणों के लिए अलग-अलग मेमोरी पतों की आवश्यकता होती है। (यह मेमोरी पतों के साथ ऑब्जेक्ट आइडेंटिटी ट्रैकिंग की अनुमति देता है।) बेस ऑब्जेक्ट और पहले व्युत्पन्न सदस्य अलग-अलग उदाहरण हैं, इसलिए उनके पास अलग-अलग पते होने चाहिए, जो क्लास के लेआउट को प्रभावित करते हुए पैडिंग को जोड़ने के लिए मजबूर करते हैं। अगर वे अलग-अलग प्रकार के होते, तो इससे कोई फर्क नहीं पड़ता; विभिन्न प्रकार की वस्तुओं को एक ही पते (उदाहरण के लिए एक वर्ग और उसका पहला डेटा सदस्य) की अनुमति है।
एडम एच। पीटरसन

46

C ++ 17 में परिवर्तन

यहां C ++ 17 अंतर्राष्ट्रीय मानक अंतिम ड्राफ्ट डाउनलोड करें

समुच्चय

C ++ 17 एग्रीगेट्स और एग्रीगेट इनिशियलाइज़ेशन को बढ़ाता है और बढ़ाता है। मानक पुस्तकालय में अब एक std::is_aggregateप्रकार का विशेषता वर्ग भी शामिल है । यहाँ धारा ११.६.१.१ और ११.६.१.२ से औपचारिक परिभाषा दी गई है (आंतरिक संदर्भ विस्तृत):

एक एग्रीगेट एक सरणी या एक वर्ग है
- कोई उपयोगकर्ता-प्रदान, स्पष्ट या विरासत में दिए गए निर्माणकर्ता,
- कोई निजी या संरक्षित गैर-स्थैतिक डेटा सदस्य
नहीं - कोई वर्चुअल फ़ंक्शन नहीं, और
- कोई वर्चुअल, निजी या संरक्षित आधार कक्षाएं नहीं।
[नोट: एग्रीगेट आरंभीकरण संरक्षित और निजी बेस क्लास के सदस्यों या कंस्ट्रक्टर्स तक पहुंचने की अनुमति नहीं देता है। - ध्यान दें]
एक समुच्चय के तत्व हैं:
- एक सरणी के लिए, सबस्क्रिप्ट ऑर्डर बढ़ाने में सरणी तत्व, या
- एक वर्ग के लिए, घोषणा क्रम में प्रत्यक्ष आधार कक्षाएं, इसके बाद प्रत्यक्ष गैर-स्थैतिक डेटा सदस्य जो नहीं हैं घोषणा पत्र में, एक अनाम संघ के सदस्य।

किया बदल गया?

  1. समुच्चय में अब सार्वजनिक, गैर-आभासी आधार वर्ग हो सकते हैं। इसके अलावा, यह कोई आवश्यकता नहीं है कि आधार कक्षाएं समुच्चय हों। यदि वे समुच्चय नहीं हैं, तो वे सूची-आरंभिक हैं।
struct B1 // not a aggregate
{
    int i1;
    B1(int a) : i1(a) { }
};
struct B2
{
    int i2;
    B2() = default;
};
struct M // not an aggregate
{
    int m;
    M(int a) : m(a) { }
};
struct C : B1, B2
{
    int j;
    M m;
    C() = default;
};
C c { { 1 }, { 2 }, 3, { 4 } };
cout
    << "is C aggregate?: " << (std::is_aggregate<C>::value ? 'Y' : 'N')
    << " i1: " << c.i1 << " i2: " << c.i2
    << " j: " << c.j << " m.m: " << c.m.m << endl;

//stdout: is C aggregate?: Y, i1=1 i2=2 j=3 m.m=4
  1. स्पष्ट रूप से डिफॉल्ट किए गए कंस्ट्रक्टर को अस्वीकृत कर दिया गया है
struct D // not an aggregate
{
    int i = 0;
    D() = default;
    explicit D(D const&) = default;
};
  1. इनहेरिटिंग कंस्ट्रक्टरों को बंद कर दिया गया है
struct B1
{
    int i1;
    B1() : i1(0) { }
};
struct C : B1 // not an aggregate
{
    using B1::B1;
};


तुच्छ वर्ग

तुच्छ वर्ग की परिभाषा C ++ 17 में कई दोषों को संबोधित करने के लिए फिर से तैयार की गई थी जिन्हें C ++ 14 में संबोधित नहीं किया गया था। परिवर्तन प्रकृति में तकनीकी थे। यहाँ 12.0.6 पर नई परिभाषा है (आंतरिक संदर्भ

एक तुच्छ रूप से
कॉपी करने वाला वर्ग एक वर्ग है: - जहां प्रत्येक कॉपी कंस्ट्रक्टर, मूव कंस्ट्रक्टर, कॉपी असाइनमेंट ऑपरेटर, और मूव असाइनमेंट ऑपरेटर या तो डिलीट या तुच्छ है,
- जिसमें कम से कम एक गैर-डिलीट कॉपी कंस्ट्रक्टर, मूव कंस्ट्रक्टर, कॉपी असाइनमेंट ऑपरेटर, या असाइनमेंट ऑपरेटर को स्थानांतरित करें, और
- जिसमें एक तुच्छ, गैर-हटाए गए विध्वंसक हो।
एक तुच्छ वर्ग एक वर्ग है जो तुच्छ रूप से प्रतिलिपि योग्य है और इसमें एक या एक से अधिक डिफ़ॉल्ट निर्माता हैं, जो सभी या तो तुच्छ हैं या हटाए गए हैं और जिनमें से कम से कम एक हटाया नहीं गया है। [नोट: विशेष रूप से, एक तुच्छ प्रतिलिपि या तुच्छ वर्ग में वर्चुअल फ़ंक्शंस या वर्चुअल बेस क्लास नहीं होते हैं। — अंत में]

परिवर्तन:

  1. C ++ 14 के तहत, एक वर्ग के तुच्छ होने के लिए, क्लास में कोई भी कॉपी / मूव कंस्ट्रक्टर / असाइनमेंट ऑपरेटर नहीं हो सकता था जो गैर-तुच्छ थे। हालांकि, तो एक परोक्ष घोषित डिफॉल्ट की निर्माता के रूप में / ऑपरेटर गैर तुच्छ और अभी तक हो सकता है परिभाषित , क्योंकि उदाहरण के लिए, वर्ग वर्ग प्रकार है कि कॉपी नहीं किया जा सकता है / ले जाया गया के एक subobject निहित के रूप में नष्ट। इस तरह के गैर-तुच्छ, परिभाषित-जैसे-हटाए गए निर्माता / ऑपरेटर की उपस्थिति पूरे वर्ग को गैर-तुच्छ बना देगी। एक समान समस्या विध्वंसक के साथ मौजूद थी। C ++ 17 स्पष्ट करता है कि ऐसे निर्माता / ऑपरेटरों की उपस्थिति के कारण वर्ग गैर-तुच्छ रूप से प्रतिलिपि योग्य नहीं होता है, इसलिए गैर-तुच्छ है, और यह कि एक तुच्छ प्रतिलिपि योग्य वर्ग में एक तुच्छ, गैर-हटाए गए विध्वंसक होना चाहिए। DR1734 , DR1928
  2. C ++ 14 ने एक तुच्छ प्रतिलिपि योग्य वर्ग की अनुमति दी, इसलिए प्रत्येक प्रतिलिपि / चाल निर्माण निर्माता / असाइनमेंट ऑपरेटर को हटाए जाने के लिए एक तुच्छ वर्ग है। यदि इस तरह की कक्षा भी मानक लेआउट थी, तो यह कानूनी रूप से कॉपी / स्थानांतरित हो सकती है std::memcpy। यह एक शब्दार्थ विरोधाभास था, क्योंकि, सभी निर्माणकर्ता / असाइनमेंट ऑपरेटरों को हटाए जाने के रूप में परिभाषित करते हुए, वर्ग के निर्माता ने स्पष्ट रूप से इरादा किया कि कक्षा को कॉपी / स्थानांतरित नहीं किया जा सकता है, फिर भी वर्ग अभी भी तुच्छ रूप से कॉपी किए गए वर्ग की परिभाषा को पूरा करता है। इसलिए C ++ 17 में हमारे पास एक नया क्लॉज है जिसमें कहा गया है कि तुच्छ रूप से कॉपी करने योग्य वर्ग में कम से कम एक तुच्छ, गैर-हटाए गए (हालांकि जरूरी नहीं कि सार्वजनिक रूप से सुलभ) कॉपी / कंस्ट्रक्टर / असाइनमेंट ऑपरेटर हो। N4148 , DR1734 देखें
  3. तीसरा तकनीकी परिवर्तन डिफ़ॉल्ट कंस्ट्रक्टर्स के साथ एक समान समस्या की चिंता करता है। सी ++ 14 के तहत, एक वर्ग में तुच्छ डिफ़ॉल्ट निर्माणकर्ता हो सकते हैं जिन्हें स्पष्ट रूप से हटाए जाने के रूप में परिभाषित किया गया था, फिर भी एक तुच्छ वर्ग हो सकता है। नई परिभाषा स्पष्ट करती है कि एक तुच्छ वर्ग में कम से कम एक तुच्छ, गैर-हटाए गए डिफ़ॉल्ट निर्माता होना चाहिए। DR1496 देखें

मानक-लेआउट कक्षाएं

दोष रिपोर्ट को संबोधित करने के लिए मानक-लेआउट की परिभाषा भी फिर से तैयार की गई। फिर से परिवर्तन प्रकृति में तकनीकी थे। यहाँ मानक से पाठ (12.0.7) है। पहले की तरह, आंतरिक संदर्भ विस्तृत हैं:

एक वर्ग S एक मानक-लेआउट वर्ग है यदि यह है:
- इसमें गैर-मानक-लेआउट वर्ग (या इस प्रकार के सरणी) या संदर्भ के गैर-स्थैतिक डेटा सदस्य
नहीं हैं , - कोई वर्चुअल फ़ंक्शन नहीं है और कोई वर्चुअल बेस क्लास नहीं है,
- सभी गैर-स्थैतिक डेटा सदस्यों के लिए समान पहुँच नियंत्रण है,
- कोई भी गैर-मानक-लेआउट बेस क्लास नहीं है,
- किसी भी प्रकार के अधिकांश एक बेस क्लास सब -जेक्ट में है,
- सभी गैर-स्टैटिक डेटा सदस्य और बिट-फ़ील्ड में हैं वर्ग और उसके आधार वर्ग को पहले एक ही कक्षा में घोषित किया गया है, और
- आधार के प्रकार (नीचे परिभाषित) के सेट M (S) का कोई तत्व आधार वर्ग 10 के रूप में नहीं है।
M (X) को निम्नानुसार परिभाषित किया गया है:
- यदि X एक गैर-संघी वर्ग प्रकार है जिसमें बिना (संभवतः विरासत में) गैर-स्थैतिक डेटा सदस्य हैं, तो M (X) सेट खाली है।
- यदि X एक गैर-यूनियन वर्ग प्रकार है, जिसके पहले गैर-स्थिर डेटा सदस्य का प्रकार X0 है (जहाँ कहा गया सदस्य एक अनाम संघ हो सकता है), M (X) के सेट M में X0 और M (X0) के तत्व होते हैं।
- यदि X एक संघ प्रकार है, तो सेट M (X) सभी M (Ui) का मिलन है और सभी Ui युक्त सेट है, जहां प्रत्येक Ui X के ith गैर-स्थैतिक डेटा सदस्य का प्रकार है। - यदि X एक गैर-वर्ग, गैर-सरणी प्रकार है, तो M (X) सेट खाली है।
- यदि X तत्व प्रकार Xe के साथ एक सरणी प्रकार है, तो सेट M (X) में Xe और M (Xe) के तत्व होते हैं।

[नोट: एम (एक्स) सभी गैर-बेस-क्लास उप-प्रकारों का प्रकार है जो एक मानक-लेआउट वर्ग में ज़ीरो ऑफ़-एक्स नोट में होने की गारंटी है]
- उदाहरण:

struct B { int i; }; // standard-layout class
struct C : B { }; // standard-layout class
struct D : C { }; // standard-layout class
struct E : D { char : 4; }; // not a standard-layout class
struct Q {};
struct S : Q { };
struct T : Q { };
struct U : S, T { }; // not a standard-layout class
- उदाहरण उदाहरण]
१०s) यह सुनिश्चित करता है कि दो उप-खंड जो एक ही वर्ग प्रकार के हैं और जो एक ही सबसे व्युत्पन्न वस्तु से संबंधित हैं, एक ही पते पर आवंटित नहीं किए गए हैं।

परिवर्तन:

  1. स्पष्ट किया गया है कि आवश्यकता है कि व्युत्पन्न पेड़ में केवल एक वर्ग "गैर-स्थैतिक डेटा सदस्य एक वर्ग को संदर्भित करता है जहां ऐसे डेटा सदस्य पहले घोषित किए जाते हैं, न कि वे वर्ग जहां उन्हें विरासत में मिला हो सकता है, और इस आवश्यकता को गैर-स्थिर बिट फ़ील्ड में विस्तारित किया जाता है" । यह भी स्पष्ट किया कि एक मानक-लेआउट वर्ग "किसी भी प्रकार के अधिकांश एक बेस क्लास सबोबिज में है।" DR1813 , DR1881 देखें
  2. मानक-लेआउट की परिभाषा ने किसी भी आधार वर्ग के प्रकार को पहले गैर-स्थैतिक डेटा सदस्य के समान प्रकार की अनुमति नहीं दी है। यह एक ऐसी स्थिति से बचने के लिए है जहां ऑफसेट शून्य पर एक डेटा सदस्य के पास किसी भी आधार वर्ग के समान प्रकार है। C ++ 17 मानक एक और अधिक कठोर, पुनरावर्ती परिभाषा प्रदान करता है "सभी गैर-बेस-क्लास सबोबिज के प्रकारों का सेट जो एक मानक-लेआउट वर्ग में शून्य ऑफसेट पर होने की गारंटी है" ताकि इस प्रकार के प्रतिबंधों को लागू किया जा सके। किसी भी आधार वर्ग के प्रकार होने से। DR1672 , DR2120 देखें ।

नोट: C ++ मानकों की समिति ने C ++ 14 पर लागू करने के लिए दोष रिपोर्ट के आधार पर उपरोक्त परिवर्तनों का इरादा किया था, हालांकि नई भाषा प्रकाशित C ++ 14 मानक में नहीं है। यह C ++ 17 मानक में है।


नोट मैंने अपने जवाब को अपडेट किया है मानक लेआउट परिवर्तन दोषों में सीडी 4 स्थिति है जिसका अर्थ है कि वे वास्तव में सी ++ 14 पर लागू होते हैं। यही कारण था कि मेरे उत्तर में उन्हें शामिल नहीं किया गया था क्योंकि मैंने अपना उत्तर लिखा था।
शफीक यघमौर

ध्यान दें, मैंने इस प्रश्न पर एक इनाम शुरू किया।
शफीक यघमौर

धन्यवाद @ शफीक्यगहमौर मैं दोष रिपोर्ट की स्थिति की समीक्षा करूंगा और तदनुसार अपना उत्तर संशोधित करूंगा।
थॉमसमैकलॉड

@ शफीकियाघमौर, सी ++ 14 प्रक्रिया की कुछ समीक्षा के बाद और यह मुझे ऐसा प्रतीत होता है, जबकि ये डीआर जून 2014 में "स्वीकार किए गए" थे। रैपरस्विल ने फरवरी 2014 इस्सकाह बैठक से भाषा की बैठक की थी जो सी ++ 14 बन गई थी। Isocpp.org/blog/2014/07/trip-report-summer-iso-c-meeting देखें "आईएसओ नियमों के अनुसार हमने औपचारिक रूप से C ++ वर्किंग पेपर के किसी भी संपादन को मंजूरी नहीं दी।" क्या मैं कुछ भूल रहा हूँ?
थॉमसमेकलॉड

उनके पास 'सीडी 4' की स्थिति है, जिसका अर्थ है कि उन्हें सी ++ 14 मोड में आवेदन करना चाहिए।
शफीक यघमौर

14

में क्या बदलाव आता है

इस प्रश्न के बाकी स्पष्ट विषय के बाद, समुच्चय का अर्थ और उपयोग हर मानक के साथ बदलता रहता है। क्षितिज पर कई महत्वपूर्ण परिवर्तन हैं।

उपयोगकर्ता-घोषित बिल्डरों P1008 के साथ प्रकार

C ++ 17 में, यह प्रकार अभी भी एक समुच्चय है:

struct X {
    X() = delete;
};

और इसलिए, X{}अभी भी संकलित करता है क्योंकि यह कुल आरंभ है - एक रचनाकार मंगलाचरण नहीं। यह भी देखें: निजी कंस्ट्रक्टर कब प्राइवेट कंस्ट्रक्टर नहीं है?

C ++ 20 में, प्रतिबंध आवश्यकता से बदल जाएगा:

कोई उपयोगकर्ता-प्रदत्त explicit, या विरासत में दिया गया निर्माणकर्ता नहीं

सेवा

कोई उपयोगकर्ता-घोषित या विरासत में दिए गए निर्माता नहीं

इसे C ++ 20 वर्किंग ड्राफ्ट में अपनाया गया है । सी ++ 20 में न तो Xयहां और न ही Cजुड़े प्रश्न में समुच्चय होगा।

यह निम्न उदाहरण के साथ एक यो-यो प्रभाव के लिए भी बनाता है:

class A { protected: A() { }; };
struct B : A { B() = default; };
auto x = B{};

C ++ 11/14 में, बेस क्लास की वजह से एग्रीगेट नहींB था , इसलिए वैल्यू-इनिशियलाइज़ेशन करता है , जो कॉल करता है , जिस बिंदु पर यह सुलभ है। यह अच्छी तरह से गठित किया गया था।B{}B::B()A::A()

C ++ 17 में, Bएक समुच्चय बन गया क्योंकि आधार वर्गों को अनुमति दी गई थी, जिसने B{}कुल-आरंभ किया। यह कॉपी-सूची-प्रारंभ करने की आवश्यकता है Aसे {}है, लेकिन से के संदर्भ से बाहर Bहै, जहां यह सुलभ नहीं है। सी ++ 17 में, यह बीमार है ( auto x = B();हालांकि ठीक होगा)।

C ++ 20 में, अब उपरोक्त नियम के बदलाव के कारण, Bएक बार फिर से एक समग्र होना बंद हो जाता है (आधार वर्ग के कारण नहीं, बल्कि उपयोगकर्ता द्वारा घोषित डिफ़ॉल्ट निर्माणकर्ता के कारण - भले ही वह डिफ़ॉल्ट हो)। तो हम वापस Bनिर्माता के माध्यम से जा रहे हैं , और यह स्निपेट अच्छी तरह से बनता है।

P960 के मानों की एक संक्षिप्त सूची से समुच्चय को आरंभ करना

एक सामान्य समस्या जो सामने आती है वह है emplace()-स्टाइल निर्माणकर्ताओं को समुच्चय के साथ उपयोग करना।

struct X { int a, b; };
std::vector<X> xs;
xs.emplace_back(1, 2); // error

यह काम नहीं करता है, क्योंकि emplaceइनिशियलाइज़ेशन को प्रभावी ढंग से करने की कोशिश करेगा X(1, 2), जो मान्य नहीं है। विशिष्ट समाधान के लिए एक कंस्ट्रक्टर को जोड़ना है X, लेकिन इस प्रस्ताव के साथ (वर्तमान में कोर के माध्यम से अपने तरीके से काम कर रहा है), समुच्चय प्रभावी रूप से उन बिल्डरों को संश्लेषित करेगा जो सही काम करते हैं - और नियमित निर्माणकर्ताओं की तरह व्यवहार करते हैं। उपरोक्त कोड C ++ 20 के रूप में संकलित होगा।

कक्षा टेम्पलेट तर्क कटौती (CTAD) एग्रीगेट्स P1021 (विशेष रूप से P1816 ) के लिए

C ++ 17 में, यह संकलित नहीं करता है:

template <typename T>
struct Point {
    T x, y;
};

Point p{1, 2}; // error

उपयोगकर्ताओं को सभी समग्र टेम्प्लेट के लिए अपना स्वयं का कटौती गाइड लिखना होगा:

template <typename T> Point(T, T) -> Point<T>;

लेकिन जैसा कि यह कुछ अर्थ में "स्पष्ट बात" है, और मूल रूप से सिर्फ बॉयलरप्लेट है, भाषा आपके लिए ऐसा करेगी। यह उदाहरण C ++ 20 (उपयोगकर्ता द्वारा प्रदान किए गए कटौती गाइड की आवश्यकता के बिना) में संकलित होगा।


हालाँकि, मैं इसे बढ़ाऊंगा, लेकिन इसे जोड़ने में थोड़ी जल्दी महसूस होती है, लेकिन मुझे कुछ भी नहीं पता चल रहा है कि C ++ 2x के पूरा होने से पहले इसे बदल दिया जाएगा।
शफीक याघमोर

@ शफीक्यगहमौर हाँ, शायद बहुत जल्दी। लेकिन यह देखते हुए कि एसडी नई भाषा सुविधाओं के लिए समय सीमा थी, ये केवल दो इन-फ्लाइट हैं जिनके बारे में मुझे पता है - सबसे खराब स्थिति मैं बाद में इनमें से एक अनुभाग को ब्लॉक कर देता हूं? मैंने अभी-अभी प्रश्न को बाउंटी के साथ सक्रिय देखा और सोचा कि यह भूल जाने से पहले झंकार करने का अच्छा समय था।
बैरी

मैं समझता हूं, मुझे इसी तरह के मामलों के लिए कई बार लुभाया गया है। मुझे हमेशा चिंता है कि कुछ बड़ा बदलाव आएगा और मैं इसे फिर से लिखने के लिए समाप्त हो जाऊंगा।
शफीक यघमौर

@ शफीकगहमौर लगता है कि यहां कुछ भी नहीं बदलने जा रहा है :)
बैरी

मुझे उम्मीद है कि यह अब अपडेट हो गया है, C ++ 20 पहले से ही जारी है
Noone AtAll
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.