मुझे किस शीर्षक को 'size_t` के लिए शामिल करना चाहिए?


95

इसके अनुसार Cppreference.com के size_t कई हेडर में परिभाषित किया गया है, अर्थात्

<cstddef>
<cstdio>
<cstring>
<ctime>

और, C ++ 11 के बाद से, में भी

<cstdlib>
<cwchar> 

सबसे पहले मुझे आश्चर्य है कि यह मामला क्यों है। इस विरोधाभास में नहीं है DRY सिद्धांत के ? हालांकि, मेरा सवाल यह है:

उपरोक्त हेडर में से कौन सा मुझे उपयोग करने के लिए शामिल करना चाहिए size_t? क्या यह बिल्कुल भी मायने रखता है?


1
संबंधित हेडर फाइलें खोलें और परिभाषा खोजें।
--६

33
@ i486 - यह भंगुर गैर-पोर्टेबल कोड लिखने का एक शानदार तरीका है!
शॉन

3
@PanagiotisKanavos सी हेडर जो C ++ मानक लाइब्रेरी का हिस्सा हैं और शायद आपके किसी भी कथित 'सच्चे C ++' हेडर में डुप्लिकेट नहीं हैं। आपकी बात क्या थी, बिल्कुल?
अंडरस्कोर_ड

14
मैं हमेशा के लिए इस्तेमाल <cstddef>कियाstd::size_t
Boiethios

4
@PanagiotisKanavos ज़रूर, आम तौर पर यह अच्छी सलाह है, लेकिन इस मामले में यह प्रासंगिक नहीं लगता है - क्योंकि कोई सी ++ प्रतिस्थापन नहीं है std::size_t, और ओपी विरासत सी कार्यों का उपयोग करने की वकालत नहीं कर रहा था, बस उनके बारे में बोली को देखते हुए टाइपडिफ को साझा करना। मुझे संदेह है कि इस सूत्र को पढ़ने वाले को इस वजह से विरासत के प्रकारों / कार्यों का उपयोग करने में गुमराह किया जाएगा, लेकिन अगर आप सुनिश्चित करना चाहते हैं कि वे ऐसा नहीं करते हैं, तो काफी उचित है!
अंडरस्कोर_ड

जवाबों:


90

यह मानते हुए कि मैं जिन कार्यों और प्रकारों का आयात कर रहा था, उन्हें कम करना चाहता था cstddef क्योंकि यह किसी भी प्रकार के कार्यों की घोषणा नहीं करता है और केवल ६ प्रकारों की घोषणा करता है। अन्य लोग विशेष डोमेन (स्ट्रिंग्स, समय, IO) पर ध्यान केंद्रित करते हैं जो आपके लिए कोई मायने नहीं रखते।

ध्यान दें कि cstddefकेवल नाम स्थान में std::size_tपरिभाषित करने की गारंटी देता है , हालांकि यह वैश्विक नाम स्थान (प्रभावी रूप से, सादे ) में भी यह नाम प्रदान कर सकता हैsize_tstdsize_t

इसके विपरीत, stddef.h(जो सी में उपलब्ध हेडर भी है) size_tवैश्विक नाम स्थान में परिभाषित करने की गारंटी देता है , और यह भी प्रदान कर सकता हैstd::size_t


3
वहाँ किसी भी गारंटी है कि size_tसे cstddefएक ही है और हमेशा दूसरों के रूप में ही हो जाएगा? ऐसा लगता है कि आम परिभाषाओं के साथ एक आम हेडर फाइल होनी चाहिए जैसे size_t...
स्नेकडोक

1
@SnakeDoc और मानो जादू के द्वारा, यहां एक और उत्तर पहले से ही 'आंतरिक' हेडर के माध्यम से हो रहा है।
अंडरस्कोर_ड

5
@SnakeDoc हाँ, और वह हेडर है cstddef
1:25 पर user253751

2
@SnakeDoc, कौन कहता है कि वे अपने स्वयं को परिभाषित करते हैं? सभी मानक कहते हैं कि यह उन हेडर को शामिल करने के बाद परिभाषित किया जाएगा, यह नहीं कहता है कि उन सभी को इसे फिर से परिभाषित करना होगा। वे सभी शामिल कर सकते हैं <cstddef>, या वे सभी कुछ आंतरिक हेडर शामिल कर सकते हैं जो सिर्फ परिभाषित करता है size_t
जोनाथन वेकली

1
है csttddefजवाब लिखने में कोई गलती? शायद cstddefमतलब है?
एरिक सोजलंड

46

वास्तव में कई हेडर के सिनॉप्सिस (C ++ मानक में शामिल) को विशिष्ट size_tरूप से शामिल किया गया है और साथ ही आगे हेडर प्रकार को परिभाषित करते हैं size_t(सी मानक के आधार पर <cX>हेडर सिर्फ आईएसओ सी <X.h>हेडर हैं जिनमें उल्लेखनीय परिवर्तन हैं जहां हटाने का size_tसंकेत नहीं दिया गया है)।

C ++ मानक हालांकि, की परिभाषा के लिए संदर्भित करता <cstddef>हैstd::size_t

  • में 18.2 प्रकार ,
  • में 5.3.3 sizeof ,
  • में 3.7.4.2 आवंटन रद्द करने कार्यों (जो 18.2 को संदर्भित करता है) और
  • में 3.7.4.1 आबंटन कार्यों (भी 18.2 को संदर्भित करता है)।

इसलिए और इस तथ्य के कारण कि <cstddef>केवल प्रकार और कोई फ़ंक्शन का परिचय देता है, मैं std::size_tउपलब्ध कराने के लिए इस शीर्ष लेख से चिपकाऊंगा ।


कुछ बातों पर ध्यान दें:

  1. के प्रकार std::size_tका उपयोग कर प्राप्य है decltypeएक शीर्ष लेख शामिल किए बिना

    यदि आप अपने कोड में किसी भी प्रकार से एक टाइफाइड लाने की योजना बना रहे हैं (अर्थात क्योंकि आप एक कंटेनर लिखते हैं और एक size_typeटंकण प्रदान करना चाहते हैं ) तो आप वैश्विक प्रकार का उपयोग कर सकते हैं sizeof, sizeof...या alignofऑपरेटर किसी भी हेडर को शामिल किए बिना अपने प्रकार को परिभाषित करने के लिए उपयोग कर सकते हैं , क्योंकि थियोस ऑपरेटर std::size_tप्रति वापसी करते हैं। मानक परिभाषा और आप उन decltypeपर उपयोग कर सकते हैं:

    using size_type = decltype(alignof(char));
  2. std::size_tstd::size_tतर्क के अनुसार कार्य हालांकि विश्व स्तर पर दिखाई नहीं दे रहे हैं।

    अंतर्निहित रूप से घोषित वैश्विक आवंटन और निपटान कार्य

    void* operator new(std::size_t);
    void* operator new[](std::size_t);
    void operator delete(void*);
    void operator delete[](void*);

    परिचय नहीं है size_t, stdया std::size_tऔर

    का उल्लेख करना stdया std::size_tतब तक बीमार है जब तक कि उपयुक्त हेडर को शामिल करके नाम घोषित नहीं किया गया हो।

  3. उपयोगकर्ता को फिर से परिभाषित नहीं किया जा सकता है, std::size_tहालांकि एक ही नामस्थान में एक ही प्रकार का उल्लेख करते हुए कई टाइपराइंड होना संभव है।

    हालाँकि, size_tभीतर की कई परिभाषाओं की घटना 7.1.3 / 3 केstd अनुसार पूरी तरह से मान्य है , इसे 17.6.4.2.1 / 1 के अनुसार किसी भी घोषणा को जोड़ने की अनुमति नहीं है :namespace std

    C ++ प्रोग्राम का व्यवहार अपरिभाषित है यदि यह नेमस्पेस std के लिए या नामस्थान std के भीतर एक नेमस्पेस में घोषणा या परिभाषा जोड़ता है जब तक कि अन्यथा निर्दिष्ट न हो।

    size_tनेमस्पेस के लिए एक उचित टाइपराइफ जोड़ना 7.1.3 का उल्लंघन नहीं करता है, लेकिन यह 17.6.4.2.1 का उल्लंघन करता है और अपरिभाषित व्यवहार की ओर जाता है।

    स्पष्टता: 7.1.3 की गलत व्याख्या न करने का प्रयास करें और std(कुछ टेम्पलेट विशेषज्ञता मामलों को छोड़कर, जहां एक टाइप्डेफ़ कोई टेम्पलेट विशेषज्ञता नहीं है) को छोड़कर घोषणाएँ या परिभाषाएँ न जोड़ें । का विस्तारnamespace std


1
आप इस तथ्य को याद करते हैं कि एक डुप्लिकेट टंकण एक नए प्रकार का परिचय नहीं देता है। यह केवल एक डुप्लीकेट टाइपफेड जोड़ता है, जो पूरी तरह से मान्य है।
मैक्सिम इगोरुशिन

@MaximEgorushkin: मेरा यह दावा नहीं है कि पुनर्परिभाषित stdटाइपफ़ीड जोड़ना अमान्य है क्योंकि डुप्लिकेट टाइपफ़ीड अवैध है। मैं बताता हूं कि यह अवैध है क्योंकि आप केवल परिभाषाओं को नहीं जोड़ सकते हैं namespace std- कोई फर्क नहीं पड़ता कि वे कानूनी होंगे।
Pixelchemist

संभावित रूप से क्या टूट सकता है, यह देखते हुए हम इन सभी मानक उद्धरणों से जानते हैं?
मैक्सिम एगोरुस्किन

12
@MaximEgorushkin: कुछ भी। यही अपरिभाषित व्यवहार के बारे में है, है ना? मुद्दा यह है कि यह हो सकता है काम या यहाँ तक कि मुद्दा यह है कि यह करता है किसी भी मनमाने ढंग से संकलक पर नहीं तोड़ कार्यक्रम मानक के अनुसार परिभाषित के व्यवहार नहीं है। या जैसा कि 'fredoverflow' ने इसे अच्छी तरह से यहाँ रखा है : "C ++ मानक में केवल वोट, अवधि है।"
Pixelchemist

मैं चाहूंगा कि आप अपनी आलोचनात्मक सोच का इस्तेमाल करें। संभावित रूप से क्या टूट सकता है?
मैक्सिम एगोरुस्किन

9

सभी मानक लाइब्रेरी हेडर फ़ाइलों की परिभाषा समान है; इससे कोई फर्क नहीं पड़ता कि आप अपने कोड में किसको शामिल करते हैं। मेरे कंप्यूटर पर, मेरे पास निम्नलिखित घोषणा है _stddef.h। यह फ़ाइल आपके द्वारा सूचीबद्ध प्रत्येक फ़ाइल में शामिल है।

/*
   Define the size_t type in the std namespace if in C++ or globally if in C.
   If we're in C++, make the _SIZE_T macro expand to std::size_t
*/

#if !defined(_SIZE_T) && !defined(_SIZE_T_DEFINED)
#  define _SIZE_T_DEFINED
#if defined(_WIN64)
   typedef unsigned __int64 size_t;
#else
   typedef unsigned int size_t;
#endif
#  if defined(__cplusplus)
#    define _SIZE_T std::size_t
#  else
#    define _SIZE_T size_t
#  endif
#endif

2
यकीन नहीं है, लेकिन मुझे लगता है कि यह संकलन समय के लिए मायने रखता है, नहीं?
इडेलेव ४६३०३५18१

@ tobi303 इस विशिष्ट प्रश्न के लिए नहीं। हां, आप आवश्यकता से बड़ा हेडर जोड़ सकते हैं, लेकिन फिर आपने पहले ही C ++ प्रोजेक्ट में C हेडर जोड़ दिया। आपको size_tपहली जगह की आवश्यकता क्यों है ?
पनियागोटिस कानावोस

यह परिभाषित करने के लिए ओएस मैक्रो सूँघने का उपयोग करने के लिए एक अच्छा विचार नहीं है size_t। आप इसे अधिक रूप से परिभाषित कर सकते हैं using size_t = decltype( sizeof( 42 ) )। लेकिन कोई ज़रूरत नहीं है, क्योंकि <stddef.h>लगभग शून्य लागत है।
चीयर्स एंड हीथ। - अल्फ

4

आप एक हेडर के बिना कर सकते हैं:

using size_t = decltype(sizeof(int));
using size_t = decltype(sizeof 1); //  The shortest is my favourite.
using size_t = decltype(sizeof "anything");

ऐसा इसलिए है क्योंकि C ++ मानक की आवश्यकता है:

का परिणाम है sizeofऔर sizeof...एक प्रकार का एक निरंतर है std::size_t। [नोट: std::size_tमानक हेडर <cstddef>(18.2) में परिभाषित किया गया है । - अंतिम नोट]

दूसरे शब्दों में, मानक की आवश्यकता है:

static_assert(std::is_same<decltype(sizeof(int)), std::size_t>::value,
              "This never fails.");

यह भी ध्यान दें, कि यह typedefघोषणा वैश्विक और stdनेमस्पेस में पूरी तरह से ठीक है , जब तक कि यह typedefएक ही टाइप-बीफ-नाम की अन्य सभी घोषणाओं से मेल नहीं खाता (गैर संकलित घोषणाओं पर एक संकलक त्रुटि जारी) ।

यह है क्योंकि:

  • Ed7.1.3.1 टाइपसेफ -नाम एक नए प्रकार को क्लास डिक्लेरेशन (9.1) या एनम डिक्लेयर करने के तरीके को पेश नहीं करता है।

  • §7.1.3.3 किसी दिए गए गैर-श्रेणी के दायरे में, एक विशेषांक का typedefउपयोग उस दायरे में घोषित किसी भी प्रकार के नाम को फिर से परिभाषित करने के लिए किया जा सकता है , जिस प्रकार से यह पहले से ही संदर्भित है।


संशयवादियों का कहना है कि यह नाम स्थान में एक नए प्रकार का जोड़ है std, और इस तरह के एक कार्य को मानक द्वारा स्पष्ट रूप से निषिद्ध है, और यह यूबी है और यह सब वहां है; मेरा कहना है कि यह रवैया अंतर्निहित मुद्दों की गहरी समझ को अनदेखा करने और इनकार करने के लिए है।

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

... अंत में, यह सब बहुत बुरा लग रहा था और बहुत खराब समझा गया था; मानकीकरण समिति ने यह नहीं कहा कि एसटीएल कंटेनरों को अपूर्ण प्रकारों के साथ काम करने के लिए कहने के अलावा कोई विकल्प नहीं था। अच्छे उपाय के लिए, हमने उस प्रतिबंध को बाकी मानक पुस्तकालय में भी लागू किया।

... रेट्रोस्पेक्ट में, अब जब तकनीक बेहतर समझ में आ रही है, तो यह निर्णय अभी भी मूल रूप से सही लगता है। हां, कुछ मामलों में कुछ मानक कंटेनरों को लागू करना संभव है, ताकि उन्हें अपूर्ण प्रकारों के साथ त्वरित किया जा सके - लेकिन यह भी स्पष्ट है कि अन्य मामलों में यह मुश्किल या असंभव होगा। यह ज्यादातर मौका था कि हमने पहले परीक्षण की कोशिश की, उपयोग करते हुए std::vector, आसान मामलों में से एक हुआ।

यह देखते हुए कि भाषा के नियमों का std::size_tठीक होना आवश्यक है decltype(sizeof(int)), ऐसा namespace std { using size_t = decltype(sizeof(int)); }करना उन चीजों में से एक है जो कुछ भी नहीं तोड़ती हैं।

C ++ 11 से पहले , एक सरल कथन में परिणाम decltypeके प्रकार को घोषित करने का कोई तरीका नहीं था और sizeofइसमें शामिल किए गए टेम्पलेट्स का एक अच्छा सौदा प्राप्त किए बिना। size_tअलग-अलग लक्ष्य आर्किटेक्चर पर उपनाम अलग-अलग होते हैं, हालांकि, यह केवल परिणाम के लिए एक नए अंतर्निहित प्रकार को जोड़ने के लिए एक सुरुचिपूर्ण समाधान नहीं होगा sizeof, और कोई मानक निर्मित-टाइप किए गए पंखे नहीं हैं। इसलिए, उस समय का सबसे पोर्टेबल समाधान size_tकुछ विशिष्ट हेडर और दस्तावेज़ में टाइप उर्फ डालना था ।

C ++ 11 में अब एक सरल घोषणा के रूप में मानक की उस सटीक आवश्यकता को लिखने का एक तरीका है।


6
@ सीन आपने जो लिखा है उसका कोई मतलब नहीं है।
मैक्सिम इगोरुशिन

15
@MaximEgorushkin उनमें से आधे ने इस कोड को नहीं समझा ... यह पूरी तरह से काम करता है। हालांकि, मुझे इस तरह से पसंद नहीं है: हेडर को शामिल करना और मानक को परिभाषित करने के लिए यह बेहतर है, इमो।
बोइथियोस

9
दोस्तों, कम से कम पूरी तरह से सही जवाब देने से पहले आप कम से कम पुतली भाषा सीखें।
फ्रैडरिक हमीदी

11
टॉम ने कहा, "एक ही चीज़ को परिभाषित करने वाले 6 मानक पुस्तकालय हेडर हैं! यह पागल है! हमें एक और केवल एक परिभाषा की आवश्यकता है size_t!" एक मिनट बाद, मैरी ने कहा, "ओएमजी! size_tमानक पुस्तकालय हेडर में 7 परिभाषाएँ हैं और एक प्रोजेक्ट हेडर टॉम संपादन कर रहा है! तीसरी पार्टी लाइब्रेरी में संभवतः अधिक हैं!" xkcd.com/927

6
हालांकि इसकी एक संभावित परिभाषा है size_t, लेकिन यह ओपी के असली सवाल का जवाब नहीं देता: यह ऐसा है जैसे मैंने हेडर के लिए कहा है कि कहां FILEघोषित किया गया है और आप अपना खुद का लिखने का सुझाव देंगे।
edmz
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.