यह FAQ एग्रिगेट्स और पीओडी के बारे में है और निम्नलिखित सामग्री को शामिल करता है:
- समुच्चय क्या हैं ?
- POD s (Plain Old Data) क्या हैं ?
- वे कैसे संबंधित हैं?
- वे कैसे और क्यों खास हैं?
- C ++ 11 के लिए क्या परिवर्तन हैं?
यह FAQ एग्रिगेट्स और पीओडी के बारे में है और निम्नलिखित सामग्री को शामिल करता है:
जवाबों:
यह लेख बल्कि लंबा है। यदि आप दोनों समुच्चय और 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 के कड़े सेट को परिभाषित कर सकते हैं
C ++ मानक से औपचारिक परिभाषा ( C ++ 03 9 ) 4 ) :
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 क्या है क्योंकि कई भाषा सुविधाएँ, जैसा कि आप देखते हैं, उनके लिए अलग तरह से व्यवहार करते हैं।
private:
उपयुक्त के रूप में सम्मिलित करें): struct A { int const a; };
तो A()
अच्छी तरह से गठित है, भले ही A
डिफ़ॉल्ट रचनाकार परिभाषा बीमार हो।
एक समुच्चय की मानक परिभाषा थोड़ी बदल गई है, लेकिन यह अभी भी बहुत समान है:
कुल एक सरणी या एक वर्ग (क्लाज 9) है जिसमें कोई उपयोगकर्ता-प्रदान किए गए निर्माता (12.1), गैर-स्थैतिक डेटा सदस्यों (9.2) के लिए कोई ब्रेस-या-इक्वलाइज़र नहीं है (9.2), कोई निजी या संरक्षित गैर-स्थैतिक डेटा सदस्य (नहीं) क्लाज 11), कोई बेस क्लास (क्लाज 10), और कोई वर्चुअल फंक्शन (10.3) नहीं।
ठीक है, क्या बदल गया?
पहले, कुल में कोई उपयोगकर्ता-घोषित निर्माता नहीं हो सकता था, लेकिन अब इसमें उपयोगकर्ता-प्रदान किए गए निर्माता नहीं हो सकते । क्या कोई अंतर है? हाँ, वहाँ है, क्योंकि अब आप निर्माणकर्ताओं की घोषणा कर सकते हैं और उन्हें डिफ़ॉल्ट कर सकते हैं:
struct Aggregate {
Aggregate() = default; // asks the compiler to generate the default implementation
};
यह अभी भी एक समुच्चय है क्योंकि एक निर्माता (या कोई विशेष सदस्य फ़ंक्शन) जो पहले घोषणा पर डिफ़ॉल्ट है, उपयोगकर्ता-प्रदान नहीं किया गया है।
अब कुल मिलाकर कोई नहीं हो सकता है गैर-स्थैतिक डेटा सदस्यों के लिए ब्रेस-या-इक्वलाइज़र । इसका क्या मतलब है? खैर, यह सिर्फ इसलिए है क्योंकि इस नए मानक के साथ, हम सदस्यों को इस तरह सीधे कक्षा में आरंभीकृत कर सकते हैं:
struct NotAggregate {
int x = 5; // valid in C++11
std::vector<int> s{1,2,3}; // also valid
};
इस सुविधा का उपयोग करना वर्ग को अब एक समुच्चय नहीं बनाता है क्योंकि यह मूल रूप से आपके स्वयं के डिफ़ॉल्ट कंस्ट्रक्टर प्रदान करने के बराबर है।
तो, क्या एक कुल मिलाकर बहुत कुछ नहीं बदला है। यह अभी भी एक ही मूल विचार है, नई सुविधाओं के लिए अनुकूलित।
POD बहुत सारे परिवर्तनों से गुजरे। POD के बारे में पिछले नियमों के बहुत सारे इस नए मानक में ढील दी गई थी, और मानक में प्रदान की जाने वाली परिभाषा को मौलिक रूप से बदल दिया गया था।
एक पीओडी का विचार मूल रूप से दो अलग-अलग गुणों पर कब्जा करना है:
इस वजह से, परिभाषा को दो अलग-अलग अवधारणाओं में विभाजित किया गया है: तुच्छ वर्ग और मानक-लेआउट वर्ग, क्योंकि ये पीओडी से अधिक उपयोगी हैं। मानक अब अधिक विशिष्ट तुच्छ और मानक-लेआउट अवधारणाओं को पसंद करते हुए, शायद ही कभी पीओडी शब्द का उपयोग करता है ।
नई परिभाषा मूल रूप से कहती है कि एक पीओडी एक ऐसा वर्ग है जो दोनों तुच्छ है और मानक-लेआउट है, और इस संपत्ति को सभी गैर-स्थैतिक डेटा सदस्यों के लिए पुनरावर्ती होना चाहिए:
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;
हम संदर्भ के लिए ड्राफ्ट 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 ( सादा पुराने डेटा ) संरचना के लिए परिभाषा अनुभाग 9
वर्गों में शामिल है जो कहता है:
एक POD संरचना 110 एक गैर-संघी वर्ग है जो एक तुच्छ वर्ग और मानक-लेआउट वर्ग दोनों है, और इसमें गैर-POD संरचना, गैर-पीओडी संघ (या इस प्रकार के सरणी) का कोई गैर-स्थैतिक डेटा सदस्य नहीं है। इसी तरह, एक पीओडी यूनियन एक संघ है जो एक तुच्छ वर्ग और मानक-लेआउट वर्ग दोनों है, और इसमें गैर-पीओडी संरचना, गैर-पीओडी संघ (या इस प्रकार के सरणी) प्रकार के गैर-स्थैतिक डेटा सदस्य नहीं हैं। POD वर्ग एक ऐसा वर्ग है जो या तो POD संरचना या POD संघ है।
जो C ++ 11 जैसा ही शब्द है।
जैसा कि टिप्पणियों में उल्लेख किया गया है कि फली मानक-लेआउट की परिभाषा पर निर्भर करती है और यह 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) सेट खाली है।
क्या आप निम्नलिखित नियमों को विस्तृत कर सकते हैं:
मै कोशिश करुॅगा:
क) मानक-लेआउट कक्षाओं में सभी गैर-स्थैतिक डेटा सदस्य एक ही अभिगम नियंत्रण के साथ होने चाहिए
यही कारण है कि सरल है: सभी गैर-स्थिर डेटा सदस्यों चाहिए सब हो 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*
प्रकार के हैं, वे अलग-अलग चीज़ों की ओर इशारा करते हैं और इस प्रकार अलियासिंग नियम को तोड़ते हैं। कृप्या मुझे सही करें।
Derived
क्या वह वर्ग होना चाहिए?
Derived
पहले सदस्य के लिए इसका आधार वर्ग होने के लिए, इसमें दो चीजें होनी चाहिए: एक आधार वर्ग, और एक सदस्य । और चूंकि पदानुक्रम में केवल एक वर्ग के सदस्य हो सकते हैं (और अभी भी मानक-लेआउट हो सकते हैं), इसका मतलब है कि इसके आधार वर्ग में सदस्य नहीं हो सकते।
यहां C ++ 17 अंतर्राष्ट्रीय मानक अंतिम ड्राफ्ट डाउनलोड करें ।
समुच्चय
C ++ 17 एग्रीगेट्स और एग्रीगेट इनिशियलाइज़ेशन को बढ़ाता है और बढ़ाता है। मानक पुस्तकालय में अब एक std::is_aggregate
प्रकार का विशेषता वर्ग भी शामिल है । यहाँ धारा ११.६.१.१ और ११.६.१.२ से औपचारिक परिभाषा दी गई है (आंतरिक संदर्भ विस्तृत):
एक एग्रीगेट एक सरणी या एक वर्ग है
- कोई उपयोगकर्ता-प्रदान, स्पष्ट या विरासत में दिए गए निर्माणकर्ता,
- कोई निजी या संरक्षित गैर-स्थैतिक डेटा सदस्य
नहीं - कोई वर्चुअल फ़ंक्शन नहीं, और
- कोई वर्चुअल, निजी या संरक्षित आधार कक्षाएं नहीं।
[नोट: एग्रीगेट आरंभीकरण संरक्षित और निजी बेस क्लास के सदस्यों या कंस्ट्रक्टर्स तक पहुंचने की अनुमति नहीं देता है। - ध्यान दें]
एक समुच्चय के तत्व हैं:
- एक सरणी के लिए, सबस्क्रिप्ट ऑर्डर बढ़ाने में सरणी तत्व, या
- एक वर्ग के लिए, घोषणा क्रम में प्रत्यक्ष आधार कक्षाएं, इसके बाद प्रत्यक्ष गैर-स्थैतिक डेटा सदस्य जो नहीं हैं घोषणा पत्र में, एक अनाम संघ के सदस्य।
किया बदल गया?
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
struct D // not an aggregate
{
int i = 0;
D() = default;
explicit D(D const&) = default;
};
struct B1
{
int i1;
B1() : i1(0) { }
};
struct C : B1 // not an aggregate
{
using B1::B1;
};
तुच्छ वर्ग
तुच्छ वर्ग की परिभाषा C ++ 17 में कई दोषों को संबोधित करने के लिए फिर से तैयार की गई थी जिन्हें C ++ 14 में संबोधित नहीं किया गया था। परिवर्तन प्रकृति में तकनीकी थे। यहाँ 12.0.6 पर नई परिभाषा है (आंतरिक संदर्भ
एक तुच्छ रूप से
कॉपी करने वाला वर्ग एक वर्ग है: - जहां प्रत्येक कॉपी कंस्ट्रक्टर, मूव कंस्ट्रक्टर, कॉपी असाइनमेंट ऑपरेटर, और मूव असाइनमेंट ऑपरेटर या तो डिलीट या तुच्छ है,
- जिसमें कम से कम एक गैर-डिलीट कॉपी कंस्ट्रक्टर, मूव कंस्ट्रक्टर, कॉपी असाइनमेंट ऑपरेटर, या असाइनमेंट ऑपरेटर को स्थानांतरित करें, और
- जिसमें एक तुच्छ, गैर-हटाए गए विध्वंसक हो।
एक तुच्छ वर्ग एक वर्ग है जो तुच्छ रूप से प्रतिलिपि योग्य है और इसमें एक या एक से अधिक डिफ़ॉल्ट निर्माता हैं, जो सभी या तो तुच्छ हैं या हटाए गए हैं और जिनमें से कम से कम एक हटाया नहीं गया है। [नोट: विशेष रूप से, एक तुच्छ प्रतिलिपि या तुच्छ वर्ग में वर्चुअल फ़ंक्शंस या वर्चुअल बेस क्लास नहीं होते हैं। — अंत में]
परिवर्तन:
std::memcpy
। यह एक शब्दार्थ विरोधाभास था, क्योंकि, सभी निर्माणकर्ता / असाइनमेंट ऑपरेटरों को हटाए जाने के रूप में परिभाषित करते हुए, वर्ग के निर्माता ने स्पष्ट रूप से इरादा किया कि कक्षा को कॉपी / स्थानांतरित नहीं किया जा सकता है, फिर भी वर्ग अभी भी तुच्छ रूप से कॉपी किए गए वर्ग की परिभाषा को पूरा करता है। इसलिए C ++ 17 में हमारे पास एक नया क्लॉज है जिसमें कहा गया है कि तुच्छ रूप से कॉपी करने योग्य वर्ग में कम से कम एक तुच्छ, गैर-हटाए गए (हालांकि जरूरी नहीं कि सार्वजनिक रूप से सुलभ) कॉपी / कंस्ट्रक्टर / असाइनमेंट ऑपरेटर हो। N4148 , DR1734 देखेंमानक-लेआउट कक्षाएं
दोष रिपोर्ट को संबोधित करने के लिए मानक-लेआउट की परिभाषा भी फिर से तैयार की गई। फिर से परिवर्तन प्रकृति में तकनीकी थे। यहाँ मानक से पाठ (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) यह सुनिश्चित करता है कि दो उप-खंड जो एक ही वर्ग प्रकार के हैं और जो एक ही सबसे व्युत्पन्न वस्तु से संबंधित हैं, एक ही पते पर आवंटित नहीं किए गए हैं।
परिवर्तन:
नोट: C ++ मानकों की समिति ने C ++ 14 पर लागू करने के लिए दोष रिपोर्ट के आधार पर उपरोक्त परिवर्तनों का इरादा किया था, हालांकि नई भाषा प्रकाशित C ++ 14 मानक में नहीं है। यह C ++ 17 मानक में है।
इस प्रश्न के बाकी स्पष्ट विषय के बाद, समुच्चय का अर्थ और उपयोग हर मानक के साथ बदलता रहता है। क्षितिज पर कई महत्वपूर्ण परिवर्तन हैं।
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
निर्माता के माध्यम से जा रहे हैं , और यह स्निपेट अच्छी तरह से बनता है।
एक सामान्य समस्या जो सामने आती है वह है emplace()
-स्टाइल निर्माणकर्ताओं को समुच्चय के साथ उपयोग करना।
struct X { int a, b; };
std::vector<X> xs;
xs.emplace_back(1, 2); // error
यह काम नहीं करता है, क्योंकि emplace
इनिशियलाइज़ेशन को प्रभावी ढंग से करने की कोशिश करेगा X(1, 2)
, जो मान्य नहीं है। विशिष्ट समाधान के लिए एक कंस्ट्रक्टर को जोड़ना है X
, लेकिन इस प्रस्ताव के साथ (वर्तमान में कोर के माध्यम से अपने तरीके से काम कर रहा है), समुच्चय प्रभावी रूप से उन बिल्डरों को संश्लेषित करेगा जो सही काम करते हैं - और नियमित निर्माणकर्ताओं की तरह व्यवहार करते हैं। उपरोक्त कोड C ++ 20 के रूप में संकलित होगा।
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 (उपयोगकर्ता द्वारा प्रदान किए गए कटौती गाइड की आवश्यकता के बिना) में संकलित होगा।