शून्य * के लिए एक वैध उपयोग है?


87

क्या void*C ++ में वैध उपयोग है ? या इसे इसलिए पेश किया गया क्योंकि C के पास था?

बस अपने विचारों को पुनः प्राप्त करने के लिए:

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

आउटपुट : मैं किसी भी स्थिति के बारे में नहीं सोच सकता, जहां मैं void*एक ज्ञात आधार वर्ग से प्राप्त चीज़ के विपरीत प्राप्त करना पसंद करूंगा ।

बस यह स्पष्ट करने के लिए कि मेरा क्या मतलब है: मैं विशेष रूप से नहीं पूछ रहा हूं कि क्या इसके लिए उपयोग-मामला है void*, लेकिन अगर कोई ऐसा मामला है जहां void*सबसे अच्छा या केवल उपलब्ध विकल्प है। जिसका जवाब नीचे के कई लोगों ने पूरी तरह से दिया है।


3
उस समय के बारे में जब आप कई प्रकार जैसे int & std :: string करना चाहते हैं?
आमिर

12
@Amir, variant, any, टैग संघ। कुछ भी जो आपको वास्तविक प्रकार की सामग्री और उपयोग करने के लिए सुरक्षित बता सकता है।
Revolver_Ocelot

15
"सी है यह" एक मजबूत पर्याप्त औचित्य है, और अधिक की तलाश करने की आवश्यकता नहीं है। जितना हो सके इससे बचना किसी भी भाषा में अच्छी बात है।
एन। 'सर्वनाम' मी।

1
जट एक बात: सी-स्टाइल एपीआई के साथ इंटरॉप इसके बिना अजीब है।
मार्टिन जेम्स

1
एक दिलचस्प उपयोग बिंदुओं के वैक्टर के लिए प्रकार का क्षरण है
पाओलो एम

जवाबों:


81

void*कम से कम आवश्यक है ::operator new( और साथ ही operator new...) और mallocप्लेसमेंट newऑपरेटर के तर्क के रूप में ।

void*हर पॉइंटर प्रकार के सामान्य सुपरपाइप के रूप में सोचा जा सकता है। तो यह बिल्कुल सूचक नहीं है void, लेकिन कुछ भी करने के लिए सूचक है।

BTW, अगर आप कई असंबंधित वैश्विक चर के लिए कुछ डेटा रखने के लिए चाहता था, आप कुछ प्रयोग कर सकते हैं std::map<void*,int> score; तो, होने की घोषणा की वैश्विक के बाद int x;और double y;और std::string s;करना score[&x]=1;और score[&y]=2;औरscore[&z]=3;

memset एक void*पता चाहता है (सबसे सामान्य)

इसके अलावा, POSIX सिस्टम में dlsym है और इसका रिटर्न स्पष्ट रूप से होना चाहिएvoid*


1
यह बहुत अच्छी बात है। मैं यह उल्लेख करना भूल गया कि मैं कार्यान्वयन पक्ष के बजाय एक भाषा उपयोगकर्ता से अधिक सोच रहा था। एक और बात जो मुझे समझ में नहीं आती है: क्या कोई फ़ंक्शन है? मैंने इसे एक कीवर्ड के रूप में और अधिक सोचा
magu_

9
new एक ऑपरेटर है, जैसे + और sizeof।
जोशुआ

7
बेशक स्मृति char *भी एक के माध्यम से वापस किया जा सकता है। वे इस पहलू पर बहुत करीब हैं, हालांकि अर्थ थोड़ा अलग है।
edmz

@Joshua। नहीं पता था कि मुझे यह सिखाने के लिए धन्यवाद। चूंकि इसमें C++लिखा गया C++है, यह पर्याप्त कारण है void*। इस साइट से प्यार होगा। एक प्रश्न पूछें बहुत कुछ सीखते हैं।
मग्गू_

3
@black पुराने दिनों में वापस, C के पास एक void*प्रकार भी नहीं था । सभी मानक पुस्तकालय कार्यों का इस्तेमाल कियाchar*
कोल जॉनसन

28

उपयोग करने के कई कारण हैं void*, 3 सबसे आम हैं:

  1. void*अपने इंटरफ़ेस में सी लाइब्रेरी का उपयोग करके बातचीत करना
  2. टाइप-विलोपन
  3. अन-टाइप की गई मेमोरी को दर्शाते हुए

रिवर्स ऑर्डर में, (या वेरिएंट) के void*बजाय (3) के साथ अन-टाइप की गई मेमोरी को चिह्नित करना char*आकस्मिक सूचक अंकगणित को रोकने में मदद करता है; इस पर बहुत कम ऑपरेशन उपलब्ध हैं, void*इसलिए आमतौर पर उपयोगी होने से पहले कास्टिंग की आवश्यकता होती है। और हां, बहुत पसंद है कि char*वहाँ कोई मुद्दा नहीं है।

टाइप-इरेज़र (2) का उपयोग अभी भी C ++ में किया जाता है, टेम्पलेट के साथ संयोजन में या नहीं:

  • गैर-सामान्य कोड बाइनरी ब्लोट को कम करने में मदद करता है, यह सामान्य कोड में भी ठंडे रास्तों में उपयोगी है
  • गैर-जेनेरिक कोड कभी-कभी जेनेरिक कंटेनर जैसे भंडारण के लिए भी आवश्यक होता है std::function

और जाहिर है, जब आप उपयोग किए गए इंटरफ़ेस void*(1) से निपटते हैं , तो आपके पास बहुत कम विकल्प होते हैं।


15

अरे हाँ। C ++ में भी कभी-कभी हम इसके void *बजाय जाते हैं template<class T*>क्योंकि कभी-कभी टेम्पलेट विस्तार से अतिरिक्त कोड बहुत अधिक वजन का होता है।

आमतौर पर मैं इसे वास्तविक प्रकार के कार्यान्वयन के रूप में उपयोग करता हूं, और टेम्पलेट प्रकार इसमें से प्राप्त होता है और कलाकारों को लपेटता है।

इसके अलावा, कस्टम स्लैब आवंटन (ऑपरेटर नए कार्यान्वयन) का उपयोग करना चाहिए void *। यह उन कारणों में से एक है कि क्यों जी ++ ने सूचक अंकगणितीय को अनुमति देने का एक विस्तार जोड़ा void *क्योंकि यह आकार 1 का था।


आपके उत्तर के लिए धन्यवाद। आप सही हैं मैं टेम्प्लेट का उल्लेख करना भूल गया। लेकिन शायद ही कभी कार्य निष्पादन के लिए टेम्प्लेट बेहतर तरीके से अनुकूल होंगे, क्योंकि शायद ही कभी कोई जुर्माना लगाया जाए। ( stackoverflow.com/questions/2442358/… )
magu_

1
टेम्प्लेट एक कोड साइज़ पेनल्टी लगाते हैं, जो ज्यादातर मामलों में एक प्रदर्शन पेनल्टी भी है।
जोशुआ

struct wrapper_base {}; template<class T> struct wrapper : public wrapper_base {T val;} typedef wrapper* like_void_ptr;एक न्यूनतम शून्य है - * - टेम्प्लेट का उपयोग करके सिम्युलेटर।
user253751

3
@ जोशुआ: आपको "सबसे" के लिए एक प्रशस्ति पत्र की आवश्यकता है।
user541686

@ मेहरदाद: L1 कैश देखें।
यहोशू

10

इनपुट: यदि हम कई इनपुट प्रकारों को अनुमति देना चाहते हैं तो हम कार्यों और विधियों को अधिभारित कर सकते हैं

सच।

वैकल्पिक रूप से हम एक सामान्य आधार वर्ग को परिभाषित कर सकते हैं।

यह आंशिक रूप से सत्य है: क्या होगा यदि आप एक सामान्य आधार वर्ग, एक अंतरफलक या समान को परिभाषित नहीं कर सकते हैं ? उन्हें परिभाषित करने के लिए आपको स्रोत कोड तक पहुंच की आवश्यकता होती है, जो अक्सर संभव नहीं होता है।

आपने टेम्प्लेट का उल्लेख नहीं किया है। हालाँकि, टेम्पलेट आपको बहुरूपता के साथ मदद नहीं कर सकते हैं: वे स्थिर प्रकारों के साथ काम करते हैं अर्थात संकलन समय पर ज्ञात होते हैं।

void*सबसे कम आम भाजक माना जा सकता है। C ++ में, आपको आमतौर पर इसकी आवश्यकता नहीं है क्योंकि (i) आप स्वाभाविक रूप से इसके साथ बहुत कुछ नहीं कर सकते हैं और (ii) लगभग हमेशा बेहतर समाधान होते हैं।

आगे भी, आप आमतौर पर इसे अन्य ठोस प्रकारों में परिवर्तित करने पर समाप्त हो जाएंगे। इसलिए char *आमतौर पर बेहतर होता है, हालांकि यह संकेत दे सकता है कि आप डेटा के शुद्ध ब्लॉक के बजाय सी-स्टाइल स्ट्रिंग की अपेक्षा कर रहे हैं। इसलिए इसके void*लिए बेहतर char*है, क्योंकि यह अन्य सूचक प्रकारों से निहित कलाकारों की अनुमति देता है।

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

एक और वैध उपयोग

जब पॉइंटर printfपॉइंटर को void*टाइप करने वाले फ़ंक्शंस के साथ पॉइंटर टाइप होगा और इसलिए, आपको एक कास्ट की आवश्यकता हो सकती है void*


7

हां, यह उतना ही उपयोगी है जितना कि भाषा की कोई अन्य चीज।
एक उदाहरण के रूप में, आप इसका उपयोग उस वर्ग के प्रकार को मिटाने के लिए कर सकते हैं, जिसे आप न्यूनतम और लचीले इंटरफ़ेस के लिए, आवश्यक होने पर सही प्रकार से डाली जा सकती हैं।

में है कि प्रतिक्रिया उपयोग का एक उदाहरण है कि आप एक विचार दे चाहिए।
मैं स्पष्टता के लिए इसे नीचे कॉपी और पेस्ट करता हूं:

class Dispatcher {
    Dispatcher() { }

    template<class C, void(C::*M)() = C::receive>
    static void invoke(void *instance) {
        (static_cast<C*>(instance)->*M)();
    }

public:
    template<class C, void(C::*M)() = &C::receive>
    static Dispatcher create(C *instance) {
        Dispatcher d;
        d.fn = &invoke<C, M>;
        d.instance = instance;
        return d;
    }

    void operator()() {
        (fn)(instance);
    }

private:
    using Fn = void(*)(void *);
    Fn fn;
    void *instance;
};

जाहिर है, यह केवल के उपयोग के गुच्छा में से एक है void*


4

बाहरी लाइब्रेरी फ़ंक्शन के साथ इंटरफ़ेसिंग जो एक पॉइंटर लौटाता है। यहाँ एक Ada एप्लिकेशन के लिए एक है।

extern "C" { void* ada_function();}

void* m_status_ptr = ada_function();

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


क्या हम autoइस मामले में इसके बजाय उपयोग नहीं कर सकते ? यह मानते हुए कि संकलन समय पर टाइप किया जाता है।
मग्गू_

आह, आजकल हम शायद कर सकते हैं। यह कोड कुछ साल पहले का है जब मैंने कुछ एड रैपर बनाए थे।
RedSonja

आदा प्रकार शैतानी हो सकता है - वे अपना स्वयं का बनाते हैं, आप जानते हैं, और इसे मुश्किल बनाने में एक व्यापक आनंद लेते हैं। मुझे इंटरफ़ेस बदलने की अनुमति नहीं थी, यह बहुत आसान था, और इसने उन शून्य बिंदुओं में छिपे हुए कुछ गंदा सामान को वापस कर दिया। ओह।
RedSonja

2

संक्षेप में, C ++ एक सख्त भाषा के रूप में (खाते में नहीं लेने वाले C अवशेष जैसे Malloc () ) को शून्य की आवश्यकता है क्योंकि इसमें सभी संभावित प्रकारों का कोई सामान्य अभिभावक नहीं है। ObjC के विपरीत, उदाहरण के लिए, जिसमें ऑब्जेक्ट है


mallocऔर newदोनों लौट आए void *, तो आपको आवश्यकता होगी, भले ही सी ++ में एक वस्तु वर्ग हो
दिमित्री ग्रिगोरीव


आप पूर्णांकों की एक सरणी कैसे आवंटित करते हैं?
दिमित्री ग्रिगोरीव

@DmitryGrigoryev operator new()लौटता है void *, लेकिन newअभिव्यक्ति नहीं होती है
MM

1. मुझे यकीन नहीं है कि मैं हर वर्ग और प्रकार से ऊपर एक वर्चुअल बेस क्लास ऑब्जेक्ट देखना चाहूंगा , 2. यदि यह गैर-आभासी ईबीसी है, तो यह कैसे अलग है ? intvoid*
लोरो

1

पहली बात जो मेरे दिमाग में आती है (जो मुझे संदेह है कि ऊपर दिए गए उत्तरों में से एक जोड़े का एक ठोस मामला है) एक वस्तु उदाहरण को विंडोज में थ्रेडप्रो पास करने की क्षमता है।

मुझे C ++ क्लासेस की एक जोड़ी मिली है, जिन्हें ऐसा करने की आवश्यकता है, उनके पास वर्कर थ्रेड इंप्लीमेंटेशन है और CreateThread () API में LPVOID पैरामीटर है, क्लास में स्टैटिक मेथड इम्प्लीमेंटेशन का एड्रेस मिलता है ताकि वर्कर थ्रेड काम कर सके वर्ग का एक विशिष्ट उदाहरण। थ्रेडप्रो में सरल स्टैटिक कास्ट काम करने के लिए उदाहरण देता है, जिससे प्रत्येक तात्कालिक वस्तु को एक एकल स्टैटिक विधि कार्यान्वयन से एक श्रमिक सूत्र प्राप्त होता है।


0

एक से अधिक विरासत के मामले में, यदि आपको किसी ऑब्जेक्ट द्वारा कब्जा की गई मेमोरी चंक के पहले बाइट के लिए एक संकेतक प्राप्त करने की आवश्यकता है, तो आप कर सकते dynamic_castहैं void*

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