2009-03-07 11 views
54

क्या निम्नलिखित के बराबर है:बूस्ट के साथ नल पॉइंटर :: shared_ptr?

std::vector<Foo*> vec; 
vec.push_back(NULL); 

जब boost::shared_ptr के साथ काम? क्या यह निम्नलिखित कोड है?

std::vector< boost::shared_ptr<Foo> > vec; 
vec.push_back(boost::shared_ptr<Foo>()); 

नोट: मैं ऐसी कई वस्तुओं को वापस धक्का दे सकता हूं। क्या मुझे कहीं वैश्विक स्थैतिक nullPtr ऑब्जेक्ट घोषित करना चाहिए? इस तरह उनमें से केवल एक का निर्माण करना होगा:

boost::shared_ptr<Foo> nullPtr; 
+4

अच्छी खबर यह है: वहाँ, आप लिख सकते हैं "vec.emplace_back();" और एक शून्य सूचक संलग्न करें :) –

+7

'boost :: ptr_vector' का उपयोग करने पर विचार करें जिसके लिए कम ओवरहेड की आवश्यकता है। – Philipp

उत्तर

0

हाँ, एक वैश्विक स्थिर नल पॉइंटर घोषणा करते हैं।

4

आप shared_ptr<Foo> के लिए वैश्विक nullPtr घोषित कर सकते हैं। लेकिन यदि आप वैश्विक नामस्थान को प्रदूषित करते हैं, तो आप shared_ptr<Bar> के लिए वैश्विक nullPtr पर क्या कॉल करेंगे?

आम तौर पर मैं सूचक के वर्ग में स्थैतिक के रूप में शून्य पीआरटी घोषित करता हूं।

#include <boost\shared_ptr.hpp> 

class Foo; // forward decl 
typedef boost::shared_ptr<Foo> FooPtr; 
class Foo 
{ 
public: 
    static FooPtr Null; 
} 
... 
// define static in cpp file 
FooPtr Foo::Null; 
... 
// use Foo Null 
vec.push_back(Foo::Null); 

इस तरह प्रत्येक वर्ग में स्थिर नल होता है।

+1

वैश्विक चर पर एक टेम्पलेटेड रूपांतरण ऑपरेटर का उपयोग कर आप एक और प्राकृतिक वाक्यविन्यास प्राप्त कर सकते हैं। मेरा जवाब देखें ... :) –

52

आपका सुझाव (shared_ptr<T> कोई तर्क के साथ कन्स्ट्रक्टर को कॉल करना) सही है। (मान 0 के साथ कन्स्ट्रक्टर को कॉल करना बराबर है।) मुझे नहीं लगता कि यह vec.push_back() को पूर्व-मौजूदा shared_ptr<T> के साथ कॉल करने से धीमा होगा, क्योंकि दोनों मामलों में निर्माण की आवश्यकता है (या तो प्रत्यक्ष निर्माण या प्रति-निर्माण)।

लेकिन अगर आप चाहते हैं "अच्छे" वाक्य रचना, आप निम्न कोड की कोशिश कर सकते:

class { 
public: 
    template<typename T> 
    operator shared_ptr<T>() { return shared_ptr<T>(); } 
} nullPtr; 

यह एक एकल वैश्विक वस्तु nullPtr है, जो निम्नलिखित प्राकृतिक वाक्य रचना के लिए सक्षम बनाता वाणी:

shared_ptr<int> pi(new int(42)); 
shared_ptr<SomeArbitraryType> psat(new SomeArbitraryType("foonly")); 

... 

pi = nullPtr; 
psat = nullPtr; 

नोट कि यदि आप इसे एकाधिक अनुवाद इकाइयों (स्रोत फ़ाइलों) में उपयोग करते हैं, तो आपको कक्षा को एक नाम देना होगा (उदाहरण के लिए _shared_null_ptr_type), nullPtr ऑब्जेक्ट की परिभाषा को एक अलग .cpp फ़ाइल में ले जाएं, और extern टी में घोषणाएं जोड़ें वह हेडर फ़ाइल जहां वर्ग परिभाषित किया गया है।

+0

अच्छा विचार दोस्त। मुझे इसे +1 करना पड़ा: पी लेकिन यहां जवाब दें http://stackoverflow.com/questions/395685/how-do-you-choose-between-a-singleton-and-an-unnamed-class/395738# 3 9 5738 –

+0

धन्यवाद दोस्तों। :) litb की पोस्ट को देखते हुए पता चलता है कि कक्षा वास्तव में नामित किया जाना चाहिए। –

+0

कुछ मूर्ख नाम: nullPtrT, NullPtrType, nullPtr_t। जो कुछ भी :) मैंने पाया कि वे एक _t जोड़ते हैं जब कुछ का केवल एक उदाहरण होता है (जैसे, nothrow_t और nullptr_t)। –

17

खैर, यह कानूनी है:

shared_ptr<Foo> foo; /* don't assign */ 

और इस राज्य में, वह किसी पर पॉइंट नहीं है।तुम भी इस संपत्ति का परीक्षण कर सकते हैं:

if (foo) { 
    // it points to something 
} else { 
    // no it doesn't 
} 

तो ऐसा करने क्यों नहीं:

std::vector < shared_ptr<Foo> > vec; 
vec.push_back (shared_ptr<Foo>); // push an unassigned one 
1

यहाँ कुछ है जो मुझे लगता है कि थोड़ा सरल है और ठीक काम करता है

(याद typedef है कि आपके दोस्त):

#include <cstdlib> 
#include <vector> 
#include <iostream> 
#include <boost/shared_ptr.hpp> 

typedef boost::shared_ptr< std::vector<char> > CharVecHandle; 

inline CharVecHandle newCharVec(std::vector<char>::size_type size) { 
    return CharVecHandle(new std::vector<char>(size)); 
} 

inline CharVecHandle newCharVec(void) { 
    return CharVecHandle(); 
} 

int main (void) 
{ 
    CharVecHandle cvh = newCharVec(); 

    if (cvh == NULL) 
     std::cout << "It's NULL" << std::endl; 
    else 
     std::cout << "It's not NULL" << std::endl; 

    std::vector<CharVecHandle> cvh_vec; 

    cvh_vec.push_back(newCharVec(64)); 
    cvh_vec.push_back(newCharVec()); 

    // or call the NULL constructor directly 
    cvh_vec.push_back(CharVecHandle()); 

    return EXIT_SUCCESS; 
} 
+0

निश्चित रूप से, 'typedef'' boost :: shared_ptr 'से देखने के लिए अच्छा है, और ओपी केवल एक प्रकार के 'फू' के साथ चिंतित है, जिस स्थिति में 'typedef' अच्छी तरह से फिट बैठता है। यदि आप विभिन्न स्मार्ट पॉइंटर प्रकारों के लिए 'टाइपपीफ' के प्रसार से बचना चाहते हैं, तो मेरा दृष्टिकोण बेहतर है। सुनिश्चित नहीं है कि आप अपने 'newCharVec()' कार्यों के साथ प्रदर्शन करने की कोशिश कर रहे हैं, क्या आप समझा सकते हैं? –

+0

@j_random_hacker: 'newCharVec' फ़ंक्शंस का उद्देश्य टाइपपीफ, सुविधा और स्थिरता के समान है। वास्तविक वस्तुओं और नल वस्तुओं को बनाने में टाइप करने और स्थिरता के लिए कम वर्ण। बात यह है कि, अगर मैं टेम्पलेट विधि का उपयोग कर रहा था, तो भी मैं शायद एक टाइपिफ़ बनाउंगा। जब भी मैं अत्यधिक जटिल प्रकार की घोषणा देखता हूं तो 'सी' पृष्ठभूमि से आ रहा है, मेरी पहली प्रवृत्ति इसे टाइप करना है। इसे ध्यान में रखते हुए, मुझे यकीन नहीं है कि वास्तव में एक विधि या दूसरे को चुनने का एक उद्देश्य कारण है, यह शैली या व्यक्तिगत वरीयता का मुद्दा हो सकता है। –

+0

ठीक है, मेरे दृष्टिकोण को प्राथमिकता देने का एक कारण यह है कि, क्योंकि मेरा 'nullPtr' टाइप-अज्ञेयवादी है, यह फ़ंक्शन टेम्पलेट्स में काम करेगा जब वेरिएबल्स को मैनिपुलेट करते हैं जिसका प्रकार अज्ञात है, जबकि आपका नहीं होगा। जैसे मैं एक फ़ंक्शन टेम्पलेट 'टेम्पलेट push_a_null_ptr (वेक्टर > & v) {v.push_back (nullPtr) लिख सकता हूं; } ', जो सभी प्रकार के' टी' के लिए काम करेगा। मैं मानता हूं कि यह एक बड़ा उल्टा नहीं है, लेकिन मुझे कोई डाउनसाइड्स नहीं दिख रहा है। –

9

सी ++ 0x में, आप बससे परिवर्तित कर सकते हैंstd::shared_ptr रहे हैं:

std::vector< boost::shared_ptr<Foo> > vec; 
vec.push_back(nullptr); 
अगले सी ++ मानक से