2010-12-13 4 views
18

मेरे पास लंबे टेम्पलेट्स के लिए टाइपपीफ के उपयोग के संबंध में एक त्वरित प्रश्न है। क्रूक्स: मैंने खुद को एक अचार में पाया है-क्लाइंट फ़ंक्शंस को स्थानीय को छोड़कर टाइपपीफ रखने के लिए एक अच्छी जगह नहीं लगती है। जबकि SO प्रश्न हैं (उदाहरण के लिए here देखें), कोई भी इसे ठीक से संबोधित नहीं करता है। कृपया ध्यान दें कि यह प्रश्न इस बात का समाधान नहीं करता है कि क्या टाइपिफ्स वांछित हैं, इस प्रकार मैंने वांछित उद्देश्यों के लिए चीजों को सरल बनाने की कोशिश की है।साझा पॉइंटर्स टाइप करने के लिए सबसे अच्छी रणनीति क्या है?

boost::shared_ptr<T> के साथ काम करते समय मेरी समस्या उत्पन्न हुई है। असल में, मैं निम्नलिखित करना चाहते हैं:

#include <boost/shared_ptr.hpp> 
typedef boost::shared_ptr<Widget> WidgetPtr; 

Widget घोषणा शीर्षक में इस typedef रखने बदसूरत लगता है। यहां दो विचारधाराएं प्रतीत होती हैं: (i) यदि Widget स्वयं अपने सदस्यों में साझा पॉइंटर्स का उपयोग नहीं करता है, तो हमने एक अतिरिक्त शामिल किया है (क्योंकि हम boost::shared_ptr टेम्पलेट क्लास घोषित करने के लिए आगे नहीं बढ़ सकते हैं-अगर मैं गलत है?) (ii) अगर हम किसी अन्य वर्ग की घोषणा के दौरान इस टाइपिफ़ का उपयोग करना चाहते हैं (उस वर्ग को कॉल करें Foo) हम Widget.h सहित Widget या WidgetFwd.h सहित घोषित करने के बजाय सर्वोत्तम प्रथाओं का उल्लंघन करते हैं ... जब तक कि यह टाइपिफ़ को बाद में डुप्लिकेट किया गया है। इसके अलावा, Widget की घोषणा के दौरान टाइपिफ़ boost::shared_ptr<Widget> को यह समझ में नहीं आता है- हम Widget की घोषणा को Widget इंटरफ़ेस का उपयोग करने के तरीके की प्रत्याशा के साथ Widget की घोषणा को मिश्रित कर रहे हैं।

ठीक है, तो यह बुरा है, लेकिन यह बदतर है, लेकिन यह बदतर है: अगर मैं ऊपर के कुछ संयोजन का प्रयास नहीं करता हूं तो मैं क्लाइंट कोड में डुप्लिकेट टाइपपीफ के साथ समाप्त होता हूं, जो असंगतता (और इसलिए, संभावित, त्रुटि) उत्पन्न करता है - पूरे बिंदु यह है कि Widget दिए गए, WidgetPtr टाइपपीफ को अपने आप में एक प्रकार के रूप में कार्य करना चाहिए। उदाहरण: हम Foo को WidgetPtr का उपयोग करने के लिए नहीं चाहते हैं, boost::shared_ptr का टाइपपीफ, जबकि Barstd::auto_ptr के लिए टाइपपीट के रूप में विजेटपीआरटी का उपयोग कर रहा है।

एक अन्य विधि (और कुछ है कि मैंने देखा है ऑनलाइन चर्चा में उल्लेख किया है में से एक) typedef Widget की एक सार्वजनिक सदस्य बनाने के लिए किया जाएगा और उसके बाद Widget::Ptr का उपयोग करें:

class Widget { 
// ... 
public: 
    typedef boost::shared_ptr<Widget> Ptr; 
}; 

फिर से, मैं डॉन ' इस तरह से (i) यह सुझाव देता है कि सूचक प्रकार किसी भी तरह वर्ग का सदस्य है और (ii) यह एक भद्दा इंटरफ़ेस की ओर जाता है। इससे भी बदतर: चूंकि मैं लिखने वाली हर कक्षा को स्मार्ट पॉइंटर्स का उपयोग करने की ओर इशारा किया जा सकता है, इसलिए मैं काल्पनिक ग्राहक की पूंछ का पीछा करता हूं। बदसूरत, बदसूरत, बदसूरत।

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

एकमात्र अन्य समाधान जिसे मैं सोच सकता हूं-और फिर मुझे यकीन नहीं है कि यह अच्छा अभ्यास माना जाता है-क्या एक यूटिलिटी हेडर होना चाहिए जिसमें टाइपिफ्स रखा गया हो, संभावित रूप से अपने नामस्थान में। इस शीर्षलेख में हम इसमें शामिल होंगे और इसके साथ किया जाएगा।

क्या मुझे कुछ स्पष्ट याद आ रही है या क्या यह सिर्फ सादा मुश्किल है?

उपरोक्त की लंबाई के लिए पीएस-माफी; मुझे समस्या को पूरी तरह से व्यक्त करने का एक आसान तरीका नहीं मिला।

+2

बीटीडब्लू- पहली जगह में टाइपिंगफिंग करने का तर्क क्या तर्क है? नाम 'shared_ptr ' नाम बहुत सरल है - एक विजेट के लिए एक साझा सूचक। यहां कोई स्पष्ट कोड ब्लोट नहीं है ('बूस्ट ::' भाग को छोड़कर) imho ... – Kos

+0

@ कोस: मुझे लगता है कि समस्या तब उत्पन्न होती है जब आपके पास विजेट की बजाय विजेट जैसी कुछ है। जैसे ही स्क्रीन स्क्रीन पर फिट नहीं होता है, आप typedef'ing के बारे में शुरू करते हैं :-) – Philipp

+0

यदि आप भविष्य में साझा पॉइंटर्स को बदलना नहीं चाहते हैं, तो टाइपइपिफ़िंग काफी आसान है। –

उत्तर

6

मुझे किसी विशेष स्मार्ट पॉइंटर के उपयोग को निर्देशित करने वाली लाइब्रेरी पसंद नहीं है, लेकिन यदि आवश्यक हो तो मैं इसे बर्दाश्त करता हूं।

यदि आप उपयोगकर्ताओं को हमेशा एक विजेट में हेरफेर करने के लिए shared_ptr का उपयोग करने के लिए मजबूर करना चाहते हैं, तो यह असंभव है, इसलिए कोशिश करने से भी परेशान न हों।

दूसरी तरफ, यदि आपके पास Widget से कोई विधि है जो boost::shared_ptr<Widget> देता है, तो एक (सेन) टाइपपीफ प्रदान करने से क्लाइंट कोड को सरल बना दिया जा सकता है। जिस स्थिति में

class Widget 
{ 
public: 
    typedef boost::shared_ptr<Widget> Ptr; 

    Ptr AccessFirstChild(); 
}; // class Widget 

यह पूरी तरह #include के लिए ठीक आवश्यक हेडर है:

इसलिए मैं एक आंतरिक typedef के उपयोग को बढ़ावा होगा।

+1

मैं इसे भी वकालत करता हूं, और विशेष रूप से यदि 'विजेट' टेम्पलेट किया गया है, तो मैं सही तरीके से काम करने वाले अन्य किसी भी दृष्टिकोण को नहीं देख सकता (यानी कक्षा के बाहर 'widget.h' में टाइपिफ़ - उदाहरण के लिए आपको लगता है कि आप जानते हैं 'विजेट' के प्रत्येक संभव * प्रकार *) – Nim

+0

मुझे लगता है कि मैंने वास्तव में अपने मूल प्रश्न में इस मामले को संबोधित नहीं किया- मुझे @ निम के बिंदु को templatic प्रकारों के लिए इस दृष्टिकोण को पसंद करने के बारे में पसंद है। – Marc

+1

तो ऐसा लगता है कि हमारे पास तीन मामलों (ढीले) हैं: (i) सुविधा के लिए टाइपिफ़ ('विजेट' अपने सदस्यों के बीच किसी भी 'shared_ptr' उदाहरणों का उपयोग नहीं करता है) - शायद ग्राहक द्वारा सबसे अच्छा किया जाता है; (ii) एक टेम्पलेट 'विजेट' के लिए टाइपिफ़-यहां 'विजेट :: पीआरटी' समझ का एक अच्छा सौदा करता है; (iii) परिभाषित सदस्यों की सुविधा के लिए टाइपिफ़ - यहां 'विजेट' हेडर में टाइपिफ़ को रखने का अर्थ भी है क्योंकि 'WidgetPtr' पहले ही इंटरफ़ेस का हिस्सा है; यदि 'विजेट' सामान्य नहीं है, तो हम कक्षा घोषणा के बाहर टाइपिफ़ कर सकते हैं। उचित सारांश? – Marc

5

आप मेरी राय में इस पर विचार कर रहे हैं। प्रत्येक व्यक्ति जो shared_ptr<Widget> रखना चाहता है उसे विजेट हेडर फ़ाइल को वैसे भी शामिल करना होगा। (जो एक अच्छा विचार आईएमओ है) Widget.h में मुझे 100% समझ देता है।

+0

हो सकता है कि मैं हूं- लेकिन इस समाधान में _interface_ के कार्यान्वयनकर्ता शामिल हैं, यह अनुमान लगाते हुए कि _implementation_ के क्लाइंट 'विजेट' को इंगित करना चाहते हैं। – Marc

+0

@Marc - 'shared_ptr' का उपयोग आम तौर पर कक्षा के अर्थशास्त्र द्वारा संचालित होता है। ऑब्जेक्ट प्रतियों का उपयोग करने के लिए 'सामान्य' मामला होगा। इसलिए मैं तर्क दूंगा कि 'widget'' कुछ साझा किया गया है जिसे 'shared_ptr' का उपयोग करके प्रबंधित किया गया है, इंटरफ़ेस का हिस्सा होना चाहिए। यह पाठ्यक्रम के वैकल्पिक उपयोग को रोकता नहीं है। –

+0

दिलचस्प। क्या आप सहमत होंगे कि 'typedef' को 'con.h' में अकेले _convenience के लिए रखा गया है (यानी, ऐसी स्थिति में जहां' विजेट' के पास कोई विशेष अर्थशास्त्र नहीं है) तब वारंट नहीं किया जाएगा? – Marc

6

इसके अलावा, यह कर भावना नहीं लगता विजेट की घोषणा के दौरान बढ़ावा :: shared_ptr typedef करने के लिए स्वयं-हम कैसे ग्राहकों विजेट इंटरफ़ेस का उपयोग करेगा के एक प्रत्याशा के साथ विजेट की घोषणा मिश्रण कर रहे हैं।

सबसे पहले, यह बिल्कुल गलत नहीं है - सब के बाद, कैसे ग्राहकों को होगा (और कर सकते हैं) इंटरफ़ेस का उपयोग करने के साधन इंटरफ़ेस के ही हिस्सा है; और सी ++ के लिए, कचरा-एकत्रित नहीं होने के कारण, वस्तुओं का स्मृति प्रबंधन उनके इंटरफ़ेस का एक महत्वपूर्ण हिस्सा है।

तो दो मामले हैं। एक मामले में, Widget अनुमान लगाएगा कि यह एक साझा सूचक के माध्यम से उपयोग किया जाएगा। इसका मतलब यह होगा कि उदाहरण के लिए। विजेट से प्राप्त बच्चे विजेट shared_ptr एस के रूप में लौटाए जाते हैं, हरविजेट ने इसे shared_ptr और इसी तरह बनाया है। Widget के समान हेडर में टाइपिफ़ WidgetPtr के लिए यह पूरी तरह से वैध होगा।

दूसरे मामले में, Widget एस प्रबंधित करने की अपेक्षा की जाएगी उदाहरण के लिए। सामान्य new और delete द्वारा। ग्राहक विशेष मामलों में shared_ptr एस का उपयोग कर सकते हैं, लेकिन कुछ भी नहीं कहता है। एक प्रिंटर संवाद दिनचर्या auto_ptr का उपयोग नहीं कर सकता है। ग्राहकों के लिए तैयार रहना है कि अगर wptr एक shared_ptr, लाइन

shared_ptr<Widget> w2(wptr->firstChild()->parent()); 

एक आपदा की ओर जाता है है।

आपका प्रश्न यह इंगित करता है कि उत्तरार्द्ध आपका मामला है। तो आईएमएचओ, आपने जो किया है वह ठीक है। ग्राहक Widget ऑब्जेक्ट्स प्रबंधित करने के अपने साधन चुन सकते हैं, जब तक कि यह अन्य क्लाइंट को प्रभावित न करे।

+0

के लिए धन्यवाद हाँ, मेरे स्केच ने बहुत सुझाव दिया कि उत्तरार्द्ध मामला है; प्रतिक्रिया के लिए धन्यवाद। – Marc

1

मैं पुस्तकालयों में अपने सी ++ कोड को ढांचा करता था। क्लाइंट खपत के लिए लाइब्रेरी में हेडर का गुच्छा होगा, सभी include/LibraryName निर्देशिका के अंदर। इसके अलावा, मेरे पास इस निर्देशिका के अंदर Fwd.h नामक एक हेडर होगा, जिसमें सभी पॉइंटर टाइपिफ के साथ सभी कक्षाओं की अगली घोषणाएं होंगी।

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

हालांकि सभी कक्षाओं को shared_ptr में रखने के लिए आवश्यक नहीं है। मैं केवल उन प्रकार के लिए पॉइंटर टाइपिफ़ी बनाउंगा जो मुझे गतिशील रूप से बनाए जाने की उम्मीद है, और इस मामले में मैं एक कारखाना की आपूर्ति करूंगा। इसमें अतिरिक्त लाभ है कि आप केवल इंटरफ़ेस प्रकारों के साथ क्लाइंट कोड की आपूर्ति करने से दूर हो सकते हैं, और अपनी लाइब्रेरी की src निर्देशिका में कंक्रीट किए गए कार्यान्वयन को छुपा सकते हैं। विशेष रूप से आपने सलाह के लिए क्या नहीं पूछा, लेकिन यह मेरी विधि की पूरी तस्वीर देता है। अंतिम बिंदु के रूप में, LibraryName.h नामक सुविधा हेडर की आपूर्ति करना भी संभव है जिसमें Fwd.h और अन्य सभी सार्वजनिक शीर्षलेख शामिल हैं।

शुभकामनाएं!

0

दूसरा हिस्सा पहले: एक नाम स्थान का उपयोग करें, अर्थात्:

namespace WidgetStuff { 
    class Widget { .. 
    typedef shared_ptr<Widget> WidgetPtr; 
    .. 

आप इसे विभाजित अप करना चाहते हैं:

namespace WidgetStuff { 
    class Widget { ... 
} 
... 
namespace WidgetStuff { 
    typedef ... 

आप पुस्तकालय लेखक हैं, तो आप खुद नाम स्थान, इसलिए किसी और को इसका आक्रमण नहीं करना चाहिए।

और अब भाग एक भी उत्तर दिया जाता है, अगर आप आप कर सकते हैं चुनें:

#include <widget.h> 
#include <widget_utils.h> 

के रूप में ऊपर नाम स्थान ऊपर विभाजित करके। प्रभाव किसी को भी उपयोगिता का उपयोग नहीं करना है, चाहे वे करते हैं, उन्हें आपके नेमस्पेस पर आक्रमण नहीं करना चाहिए, इसलिए जब तक यह आपके नामस्थान में नहीं है, तब तक वे विजेटपीआरआर का मतलब कुछ और करने के लिए स्वतंत्र हैं।

1

मैं आमतौर पर टाइपिंग को आसान बनाने के लिए इस दृष्टिकोण का उपयोग करता हूं और कक्षाओं के लिए एक सामान्य साझा सूचक इंटरफ़ेस बनाता है। ध्यान दें कि यह सी ++ 0x है।

#include <iostream> 
#include <memory> 

template <class T> 
struct SharedVirtual 
{ 
    typedef std::shared_ptr<T> VPtr; 
}; 

template <class T> 
struct Shared 
{ 
    typedef std::shared_ptr<T> Ptr; 

    template <class... P> 
    static Ptr ptr(P&&... args) 
    { 
     return std::make_shared<T>(std::forward<P>(args)...); 
    } 
}; 

class Foo : public SharedVirtual<Foo> 
{ 
    public: 
     virtual void foo() const = 0; 
}; 

class Test : public Foo, public Shared<Test> 
{ 
    public: 
     void foo() const { std::cout << "Hai u!" << std::endl; } 
}; 

void print(const Foo::VPtr& ptr) 
{ 
    ptr->foo(); 
} 

int main() 
{ 
    auto ptr = Test::ptr(); 
    print(ptr); 
} 
2

मेरे दृष्टिकोण (underbar प्रकार का उपयोग कर, सिर्फ इसलिए कि यह है कि कैसे मैं यह कर)

class Type 
{ 
    public: 
     typedef shared_ptr<Type>  ptr; 
     typedef shared_ptr<const Type> const_ptr; 
}; 

मैं const_ptr संस्करण पाया है सुंदर रफ़ू उपयोगी है।

+0

यह वही है जो मैं इस समय पर विचार कर रहा हूं, क्योंकि आपको अक्सर निरंतर उदाहरणों ** और ** को परिवर्तनीय उदाहरणों के लिए स्मार्ट पॉइंटर्स की आवश्यकता होती है। –

संबंधित मुद्दे

 संबंधित मुद्दे