क्या 'नया' में `नया` है?


84

इस new int;तरह की अभिव्यक्ति int * x = new int;एक नई अभिव्यक्ति है । "नए ऑपरेटर" शब्द का उपयोग "नई अभिव्यक्ति" के साथ परस्पर रूप से किया जाता है, उदाहरण के लिए इस प्रश्न में: 'नए ऑपरेटर' और 'ऑपरेटर नए' के ​​बीच अंतर?

क्या यह कहना सही है कि newएक नई अभिव्यक्ति में प्रयोग किया जाने वाला कीवर्ड एक ऑपरेटर है? क्यों या क्यों नहीं?

यदि नहीं, तो क्या एक नई अभिव्यक्ति को "नया ऑपरेटर" कहने का कोई औचित्य है?

मुझे एक संचालक के गठन के लिए एक आधिकारिक परिभाषा खोजने में समस्या हो रही है।

मैं पहले से ही ऑपरेटर नए के बीच के अंतर को समझता हूं जो एक ऑब्जेक्ट के लिए मेमोरी आवंटित करता है और "नई अभिव्यक्ति" जो अंततः कॉल कर सकता है operator new


4
@ रॉग - बात यहाँ newकी तरह sizeofहै। और मुझे लगता है कि C ++ समुदाय के अधिकांश लोग sizeofएक ऑपरेटर के रूप में सोचते हैं । sizeofइसके प्रभावों का वर्णन करते समय स्टैंसर " ऑपरेटर" को भी संदर्भित करता है ।
स्टोरीटेलर - अनसलैंडर मोनिका

2
@ StoryTeller-UnslanderMonica मेरी दूसरी टिप्पणी (अब एक उत्तर में स्थानांतरित) से जारी है, के साथ sizeof, मैं कहूंगा कि एक अभिव्यक्ति का संचालक होगा sizeof(<type>)। और +एक एकता अभिव्यक्ति के लिए एक ऑपरेटर है <type> <op> <type>। कम से कम मेरी व्याख्या / व्याख्या है, इस पर मुझे सही करने के लिए स्वतंत्र महसूस करें।
दुष्ट

2
@ रॉग - वास्तव में। यही कारण है कि मैं तर्कपूर्ण पाठ का तर्क दूंगा, जबकि एक ऑपरेटर के रूप में दूसरे से नहीं जबकि एक के रूप में refferring।
स्टोरीटेलर -

1
स्वीकृत उत्तर के लिए एक साइड नोट: newएक ऑपरेटर है या नहीं, इसकी परवाह किए बिना , एक अभिव्यक्ति और एक ऑपरेटर के बीच अंतर है । जैसे, new intयह एक अभिव्यक्ति है क्योंकि यह किसी चीज़ का मूल्यांकन करता है। यदि newएक ऑपरेटर माना जाता है, तो केवल "नया" भाग new intऑपरेटर है (यानी, यह अपनी अलग चीज है)। वैचारिक रूप से, एक ऑपरेटर एक ऐसी चीज है जो कुछ और पर कार्य करता है।
फिलिप मिलोवानोविक

जवाबों:


140

newमें new intऑपरेटर नहीं माना जाता है। यह भी माना जाता नहीं है नहीं एक ऑपरेटर।

सी ++ मानक वास्तव में अस्पष्ट है, और यहां तक ​​कि असंगत भी, जो एक 'ऑपरेटर' का गठन करता है। जब आपरेटिंग ऑपरेटर्स (जैसा कि लेक्सिंग और प्रीप्रोसेसिंग के दौरान परिभाषित किया गया है), यह उन्हें "पंक्चुएटर्स" (चीजों की तरह () के साथ सूचीबद्ध करता है , लेकिन वास्तव में सामान्य रूप से कभी भी पंचर के लिए कोई नियम नहीं देता है। यह newएक कीवर्ड और एक ऑपरेटर दोनों के रूप में सूचीबद्ध होता है । यह sizeofकीवर्ड के सेट में सूचीबद्ध होता है, लेकिन ऑपरेटरों के सेट में नहीं, लेकिन बाद में इसे ऑपरेटर के रूप में संदर्भित करता है।

यहाँ यह स्पष्ट है कि C ++ मानक समिति का संबंध अत्यधिक संसार के "ऑपरेटरों" और "गैर-ऑपरेटरों" से अलग होने से नहीं है। ऐसा इसलिए है क्योंकि वास्तव में इसकी कोई आवश्यकता नहीं है। कोई व्याकरणिक नियम नहीं है जो सभी ऑपरेटरों या सभी गैर-ऑपरेटरों पर लागू होते हैं। अतिभारित ऑपरेटरों के सेट की तरह महत्वपूर्ण सेट, अलग से दिए गए हैं; बाइनरी अंकगणितीय अभिव्यक्तियों जैसी चीजों के लिए व्याकरणिक नियम एक बार में दिए जाते हैं।

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


6
सी और सी ++ मानक दोनों ही उनकी शब्दावली के बहुत से संबंध में टेढ़े हैं, क्योंकि उन्हें उम्मीद थी कि पाठकों को अनुमान होगा कि अगर अंतराल या अस्पष्टता थी, तो इसका मतलब यह था कि क्या वे इस तरह के चूक का उपयोग करने का प्रयास कर सकते हैं या नहीं "अनुकूलन" का औचित्य सिद्ध करने के लिए "मामलों में मानकों के लेखकों ने पर्याप्त रूप से बेतुका सोचा होगा कि उन्हें स्पष्ट रूप से मना करने की कोई आवश्यकता नहीं थी।
सुपरकाट

मानक इस तरह से मानव विवरण में अस्पष्ट हो सकता है, लेकिन वहाँ कीवर्ड है operatorऔर मुझे लगता है कि, जब कोई सटीक विलम्ब के लिए पूछता है, तो उस कीवर्ड के साथ काम करने वाली चीजों के लिए अंग्रेजी शब्द "ऑपरेटर" का उपयोग करना उचित है। इस संदर्भ में, new, new[], delete, delete[], co_await, कुछ typecasts, और वस्तुओं के लिए उपयोगकर्ता परिभाषित शाब्दिक के रूपांतरण ऑपरेटरों होगा।
हेमफ्लिट

@ किफ़्लिट ऑपरेटर्स operatorकीवर्ड को पूर्व निर्धारित करते हैं , और ऐसी चीज़ों को शामिल करते हैं .जिनका उपयोग operatorकीवर्ड के साथ नहीं किया जा सकता है । अगर मुझे गनपॉइंट पर "ऑपरेटर" की परिभाषा के साथ आने के लिए मजबूर किया गया था, तो मेरा दिमाग "ओवरलोडेबल ऑपरेटर" पर नहीं जाएगा।
स्नेफेल

अस्पष्ट अंग्रेजी शब्द "ऑपरेटर" के @ स्नेफ़ेल का उपयोग कीवर्ड को दर्शाता है operator, हाँ। अगर मुझे इस बात का पूरा-पूरा अनुमान था कि ऑपरेटर क्या है या क्या नहीं है, तो मैं एक सटीक चीज के साथ जाऊंगा, जो कि व्याकरण में सटीक रूप से परिभाषित है। हर रोज संचार में, मुझे हर समय उतनी सटीकता की आवश्यकता नहीं होगी।
हेमफ्लिट

मैं आसानी से मानता हूँ कि यह एक सटीक परिभाषा है। यह सिर्फ एक अच्छा नहीं है।
स्नेफेल

16

क्या यह कहना सही है कि newएक नई अभिव्यक्ति में प्रयोग किया जाने वाला कीवर्ड एक ऑपरेटर है? क्यों या क्यों नहीं?

नहीं। newएक में नई अभिव्यक्ति यदि किसी कीवर्ड का पहचान करने है नई अभिव्यक्ति

एक नई अभिव्यक्ति कॉल एक operator newया operator new[]भंडारण प्राप्त करने के लिए। यह उस संग्रहण को आरंभिक भी करता है, और यदि आरंभीकरण फेंकता है, तो उसे ( operator deleteया operator delete[]) के साथ आबंटित किया जाता है।

इसमें एक स्पष्ट अंतर है, इसमें operator newकेवल एक अधिभार उपयोगकर्ता-बदली जाने वाली फ़ंक्शन के रूप में संदर्भित किया गया है , और एक नया-अभिव्यक्ति इस फ़ंक्शन को कॉल करने से अधिक है।

संदर्भ: 7.6.2.8/10 [expr.new]

एक नई-अभिव्यक्ति एक आवंटन फ़ंक्शन ( [basic.stc.dynamic.allocation]) को कॉल करके ऑब्जेक्ट के लिए भंडारण प्राप्त कर सकती है । यदि अपवाद को फेंककर नई-अभिव्यक्ति समाप्त हो जाती है, तो यह एक डिक्लोकेशन फ़ंक्शन को कॉल करके स्टोरेज जारी कर सकता है। यदि आबंटित प्रकार एक गैर-सरणी प्रकार है, तो आबंटन फ़ंक्शन का नाम है operator newऔर डीललोकेशन फ़ंक्शन का नाम है operator delete। यदि आबंटित प्रकार एक सरणी प्रकार है, तो आबंटन फ़ंक्शन का नाम है operator new[]और डीलक्लबेशन फ़ंक्शन का नाम है operator delete[]


प्रतिधारण के तरीके पर विचार करें, कि हम दोनों को परिभाषित करते हैं

T operator+(T, T);
void* T::operator new(std::size_t);

कुछ प्रकार के टी के लिए, फिर किसी भी रूप में इसके अलावा:

T a, b;
T c = a + b;
T d = T::operator +(a, b);

समान है। ऑपरेटर कॉल के लिए इनफ़िक्स नोटेशन सिंटैक्टिक शुगर है।

आवंटन हालांकि, बहुत अलग तरह से व्यवहार करता है:

T *p = new T;
// does much more than
void *v = T::operator new(sizeof(T));

तो यह नए-अभिव्यक्ति सिंथैटिक चीनी को कॉल करने के लिए उचित नहीं है operator new। इस प्रकार, newकीवर्ड केवल कॉल करने के लिए फ़ंक्शन का चयन नहीं कर रहा है। यह नहीं हो सकता है, या इसे उस operator deleteफ़ंक्शन का उल्लेख करना होगा जिसे कॉल भी किया जा सकता है।


2
" operator newएक अधिभार ऑपरेटर है" - यह है ?! मुझे नहीं लगता कि इतना: operator + नहीं है एक overloadable ऑपरेटर - +है, और आप एक के माध्यम से भार के परिभाषित समारोह कहा जाता है operator +
कोनराड रुडोल्फ

1
नहीं, मैंने इसका उत्तर यह बताते हुए दिया कि ऑपरेटर एक विशिष्ट फ़ंक्शन है जिसे नई-अभिव्यक्ति के भाग के रूप में कहा जाता है। एक नई-अभिव्यक्ति एक कीवर्ड द्वारा पहचानी गई अभिव्यक्ति है, और यह कॉल करने के लिए एक उपयुक्त ऑपरेटर ढूंढती है।
बेकार

1
मैं अभी भी नहीं देख रहा हूँ कि कैसे newयह खोजशब्द की स्थिति को संबोधित करता है क्योंकि यह एक नई अभिव्यक्ति में प्रकट होता है।
जॉन बोलिंगर ने

6
दरअसल, तथ्य यह newहै कि ऑपरेटर ओवरलोडिंग के अधीन है कि उत्तर हां होना चाहिए , new(खुद) एक ऑपरेटर है।
जॉन बोलिंगर

2
मानक केवल एक अभिव्यक्ति को संदर्भित करता है जो एक ऑपरेटर को भी बुलाता है। वे पुनरावर्ती होने के बिना एक ही चीज नहीं हो सकते हैं, इसलिए पार्सिमेनियस व्याख्या यह है कि अभिव्यक्ति और ऑपरेटर बिल्कुल और केवल वही हैं जो मानक कहते हैं कि वे हैं।
बेकार

12

मैं इसे भ्रम से बचने के लिए केवल नई अभिव्यक्ति कहूंगा, void* operator new ( std::size_t count )जिसके साथ केवल नई अभिव्यक्ति चालान (आवंटन मेमोरी, जीवनकाल शुरू करना, निर्माणकर्ता) को प्रक्रिया के हिस्से के रूप में मेमोरी आवंटित करता है ।

इसके साथ समस्या newयह है कि यह केवल कॉल करने से अधिक है operator new। कौन सा एक सा है क्योंकि के लिए भ्रामक केवल कॉल ।x + y+operator +


9

यह [expr.new] द्वारा शासित होता है , जो स्पष्ट रूप से एक नई-अभिव्यक्ति के बीच अंतर करता है और एक आवंटन फ़ंक्शन को कॉल करने के माध्यम से एक नई अभिव्यक्ति कैसे भंडारण प्राप्त कर सकती है , जिसका नाम है operator new। विशेष रूप से, [expr.new] / 8 [ जोर मेरा] से:

एक नई अभिव्यक्ति ऑब्जेक्ट के लिए एक आवंटन फ़ंक्शन ([basic.stc.dynamic.allocation)) को कॉल करके प्राप्त कर सकती है । यदि अपवाद को फेंककर नई-अभिव्यक्ति समाप्त हो जाती है, तो यह एक डिक्लोकेशन फ़ंक्शन को कॉल करके भंडारण जारी कर सकता है। यदि आबंटित प्रकार एक गैर-सरणी प्रकार है, तो आवंटन फ़ंक्शन का नाम हैoperator new और डीलक्लोलेशन फ़ंक्शन का नाम ऑपरेटर हटाता है। यदि आबंटित प्रकार एक सरणी प्रकार है, तो आबंटन फ़ंक्शन का नाम ऑपरेटर हैnew[] और डीलक्लोलेशन फ़ंक्शन का नाम ऑपरेटर है delete[]


क्या यह कहना सही है कि newएक नई अभिव्यक्ति में प्रयोग किया जाने वाला कीवर्ड एक ऑपरेटर है?

विशेष रूप से, उदाहरण, गैर-आदर्श के, [expr.new] / 4 के इस फ़ंक्शन को ऑपरेटर फ़ंक्शन के रूप में वर्णित करते हैं; "[...] newऑपरेटर" :

[...] इसके बजाय, नए ऑपरेटर के स्पष्ट रूप से संक्षिप्त संस्करण का उपयोग किया जा सकता है [...]


3
जवाब के लिए धन्यवाद। मेरे द्वारा प्राप्त किए गए उत्तरों की संख्या से, ऐसा लगने लगा है कि हो सकता है कि सख्त भाषा न हो जो इस प्रश्न का उत्तर दे, एक रास्ता या कोई अन्य। इसलिए गैर-प्रामाणिक पाठ सबसे अच्छा सबूत होने के कारण समाप्त हो सकता है।
फ्रांस्वा एंड्रीक्स

8

नहीं।

ठीक है, हाँ, इस अर्थ में कि ऐसे लोग मौजूद हैं जो एक ऑपरेटर के रूप newमें विचार करते हैं new int। हालांकि, यह राय मानक के साथ बाधाओं पर (ज्यादातर) है।

सबसे पहले, [lex.operators/1]भाषा में ऑपरेटरों को सूचीबद्ध करता है। यह सोचकर मूर्ख मत बनो कि ये "प्रीप्रोसेसिंग ऑपरेटर" हैं, या तो; शाब्दिक संचालकों के अर्थ में ऐसा कोई भेद नहीं है । यह समझ में नहीं आता है, या तो, क्योंकि आप (उदाहरण के लिए) ++एक मैक्रो नहीं कर सकते ।

newवास्तव में, एक खोजशब्द (प्रति [lex.key/1]) है।

इसके बाद, हम नई अभिव्यक्ति को देखते हैं। यह वह जगह है जहाँ चीजें थोड़ी अधिक ऊनी हो जाती हैं। उदाहरण के लिए, निम्नलिखित शब्द निम्नलिखित है [expr.new/4]:

इसके बजाय, नए ऑपरेटर के स्पष्ट रूप से संक्षिप्त संस्करण का उपयोग यौगिक प्रकारों की वस्तुओं को बनाने के लिए किया जा सकता है

मैं इसे एक संपादकीय त्रुटि मानता हूं, क्योंकि यह ऊपर दी गई परिभाषाओं के साथ है, और उस खंड में कहीं और नहीं होता है।

फिर हम ऑपरेटर को ओवरलोडिंग पर आते हैं । ऑपरेटर घोषणा के लिए इसके व्याकरणिक उत्पादन में, टर्मिनल लिस्टिंग चीजों (सहित new) को ऑपरेटर ( [over.oper.general/1]) नाम दिया गया है । मुझे नहीं लगता कि हमें इस बारे में चिंता करने की आवश्यकता है। व्याकरण में टर्मिनलों के नाम का कभी भी शब्दों की परिभाषा प्रस्तुत करने का इरादा नहीं है। आखिरकार, आपके पास और अभिव्यक्ति है कि _does बिटवाइज़ और ऑपरेशन करने की आवश्यकता नहीं है; यह सिर्फ एक समानता-अभिव्यक्ति हो सकती है :

और अभिव्यक्ति :
   समानता-अभिव्यक्ति
   और अभिव्यक्ति & समानता-अभिव्यक्ति

इस तरह के व्याकरणों को परिभाषित करना आम है, और यह निश्चित रूप से इसका मतलब यह नहीं है कि प्रत्येक समानता-अभिव्यक्ति को किसी भी तरह से बिटवाइज़ और ऑपरेटर के आह्वान माना जाना चाहिए।

अंत में, कुछ ने दावा किया है कि निम्नलिखित शब्दांकन (ऑपरेटर ओवरलोडिंग सेक्शन में भी) इस बात का प्रमाण है कि newकिसी तरह अब, अलगाव में, जादुई रूप से एक ऑपरेटर है:

ऑपरेटरों new[], delete[], (), और []एक से अधिक टोकन से बनते हैं

उनके लिए मैं कहता हूं, न केवल newसूचीबद्ध नहीं है, लेकिन यह "ऑपरेटर" शब्द का स्पष्ट रूप से "व्यापक रूप से" उन चीजों का उपयोग कर रहा है जो अतिभारित हो सकते हैं ", भले ही newअपने आप में अभी भी एक ऑपरेटर नहीं है । यह एक गैर-मानक नोट में भी है, जिसे आपको उन सभी को बताना चाहिए जो आपको जानना चाहिए।

और, जैसा कि आप खुद को इंगित करते हैं, हम पहले operator newसे ही कुछ और मानते हैं।


1
[lex.operators] स्पष्ट रूप से अपूर्ण है (और पूरा होने का मतलब नहीं है!), क्योंकि [expr.sizeof] मानक रूप से कहते हैं कि sizeofएक ऑपरेटर भी है। [expr.throw] के संबंध में कम स्पष्ट है, throwलेकिन यह अभी भी एक "ऑपरेंड" की बात करता है throw, जिसका अर्थ है कि throwएक ऑपरेटर है।
कोनराड रुडोल्फ

7

जबकि मुझे पता है कि आप एक शब्दार्थिक उत्तर की तलाश में हैं, जहाँ तक मेरी राय है कि यह एक "कीवर्ड" है (जैसा कि यह स्पष्ट रूप से आरक्षित है), और मुझे लगता है कि हम दोनों जानते हैं कि यह मेमोरी आवंटन के लिए C ++ का निर्माण है। उस ने कहा, जब मैं C ++ के "ऑपरेटर" के बारे में सोचता हूं, तो मैं एक सेट इनपुट / आउटपुट के साथ कार्यों के बारे में सोचता हूं जो विशिष्ट प्रकारों के लिए ओवरराइड किया जा सकता है। नया सभी प्रकारों के लिए समान है (और अधिक भ्रमित होने पर इसे ओवरराइड किया जा सकता है)।

यह सुनिश्चित नहीं है कि आधिकारिक गोपनीयता कैसे है, लेकिन:

नई-अभिव्यक्ति उचित आवंटन फ़ंक्शन को कॉल करके भंडारण आवंटित करती है। यदि प्रकार एक गैर-सरणी प्रकार है, तो फ़ंक्शन का नाम ऑपरेटर नया है। यदि प्रकार एक सरणी प्रकार है, तो फ़ंक्शन का नाम ऑपरेटर नया है []

https://en.cppreference.com/w/cpp/language/new

इसके बाद लगता है कि new <type>स्मृति को आवंटित करने के लिए एक अभिव्यक्ति है, जबकि newउस अभिव्यक्ति के लिए ऑपरेटर है।

उसी तर्क का उपयोग करना:

  • sizeofअभिव्यक्ति के लिए एक "ऑपरेटर" है sizeof(<type>)(हालांकि sizeofएक "संकलन-समय" ऑपरेटर है, जो हमारे द्वारा उपयोग किए जाने से थोड़ा अलग है)
  • + एक अभिव्यक्ति के लिए एक ऑपरेटर है <type> <operator> <type>
  • throw अभिव्यक्ति के लिए एक ऑपरेटर है throw <throwaable>

उस तर्क से, []()एक ऑपरेटर भी है? है for? है throw?
कोनराड रुडोल्फ

1
@KonradRudolph हाँ मैं कहूँगा [] और ()अलग ऑपरेटरों का गठन। फिर forसे पूरी तरह से एक कीवर्ड है, लेकिन जहां मैं एक ऑपरेटर होने का परिसीमन करूंगा, वह पहला हिस्सा ओवरराइड होने में सक्षम था। तकनीकी रूप से, sizeofएक ऑपरेटर नहीं है, जो कि C ++ का सच है कि यह एक प्रीप्रोसेसिंग अभिव्यक्ति का अधिक है। और throwएक अभिव्यक्ति के एक ऑपरेटर हैthrow <throwable>
दुष्ट

मेरा खास मतलब था []() से संयोजन में जब एक मेमने को परिभाषित । लेकिन आपका उत्तर भी दिलचस्प है क्योंकि (सी ++ में) उत्तर संदर्भ पर निर्भर करता है: इन foo(), ()(ओवरलोड) ऑपरेटर है; में (1 + 2)यह सब पर एक ऑपरेटर नहीं है (कुछ अन्य भाषाओं में, विशेष रूप से अनुसंधान, इस अलग है)। वैसे भी, भारी मापदंड पर्याप्त नहीं है। Overloadable नहीं होने के बावजूद सी में बातें ++ जो स्पष्ट ऑपरेटर हैं के बहुत सारे हैं ( ., ::, :?, दोनों sizeof रों, आदि)।
कोनराड रुडोल्फ

1
आह, []()एक लंबोदर के रूप में परिभाषित करने के लिए एक मुश्किल जानवर है (विशेषकर क्योंकि मैं अपने सी ++ पर गति के लिए नहीं हूं)। इसलिए यहां मैं अभी भी [] ()एक लंबोदर अभिव्यक्ति के विभिन्न ऑपरेटरों का गठन करने के लिए कहूंगा , लेकिन मुझे यकीन नहीं है कि क्या आप यह तर्क देंगे कि उन्हें ओवरराइड नहीं किया जा सकता है, या यदि लंबोदर को लागू करने / घोषित करने का बहुत ही कार्य मूल लैम्डा को ओवरराइड करने का गठन करता है (जैसे) जावा में)। भाषा का डिज़ाइन वहाँ के विज्ञान पर एक कला के रूप में बनने लगा है। जहां तक ( ... ), मैंने उपयोग किए जाने वाले अधिकांश लंग्स में एक विभाजक है, लेकिन मैं आर असली में एक जेंडर ले जाऊंगा
दुष्ट

2
साइड नोट के रूप में, आर में सब कुछ एक फ़ंक्शन है और सब कुछ है फिर से परिभाषित किया जा सकता है। कोई व्यापक मानक संदर्भ नहीं है और मुझे यकीन नहीं है कि कोष्ठक को ऑपरेटर माना जाता है, लेकिन उन्हें फिर से परिभाषित किया जा सकता है; वास्तव में, अभिव्यक्ति (a + b)फ़ंक्शन कॉल `(` (ए + बी) या, वास्तव में, `(` (`+` (ए, बी)), जहां `एक्स` का उपयोग एक नाम बनाने के लिए समान है। xविशेष रूप से (जैसे कि एक infix ऑपरेटर) के बजाय एक फ़ंक्शन कॉल के लिए वाक्यविन्यास।
कोनराड रूडोल्फ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.