2015-05-13 2 views
10

मैं ऐसी परिस्थिति में हूं जहां मेरे पास दो वर्गों की परिभाषाओं के बीच एक परिपत्र निर्भरता पाश है, जहां तक ​​(जहां तक ​​मैं कह सकता हूं) दोनों वर्गों को अन्य प्रकारों को सही तरीके से परिभाषित करने के लिए एक पूर्ण प्रकार की आवश्यकता होती है।आकार लेने के लिए व्यावहारिक रूप से सुरक्षित (std :: unordered_map <std :: string, T>) सभी टी के लिए समान है?

सरल शब्दों में, मैं क्या क्या चल रहा है की सरलीकृत संस्करण की आवश्यकता है:

struct Map; 

struct Node { 
    // some interface... 
private: 
    // this cannot be done because Map is an incomplete type 
    char buffer[sizeof(Map)]; 
    // plus other stuff... 
    void* dummy; 
}; 

struct Map { 
    // some interface... 
private: 
    // this is Map's only member 
    std::unordered_map<std::string, Node> map_; 
}; 

स्थिति, ऊपर से वास्तव में अधिक जटिल है Node के बाद से वास्तव में एक प्रकार का प्रकार (boost::variant के समान होने जा रहा है) जो प्रीलोकेटेड (और उचित संरेखण के साथ, जिसे मैं इस सरलीकरण में अनदेखा कर रहा हूं) में स्पष्ट रूप से एकाधिक प्रकार की वस्तुओं में से एक को बनाने के लिए प्लेसमेंट नया का उपयोग करता हूं: बफर इसलिए sizeof(Map) नहीं बल्कि कुछ गणना की स्थिरता पर निर्भर है sizeof(Map)

समस्या यह है कि sizeof(Map) उपलब्ध नहीं है जब Map केवल आगे घोषित किया गया है। इसके अलावा, अगर मैं Node पहले घोषित करने के लिए घोषणाओं का क्रम बदलता हूं, तो Map का संकलन विफल रहता है, std::unordered_map<std::string, Node> को तत्काल नहीं किया जा सकता है जब Node कम से कम एक अपूर्ण प्रकार है, कम से कम उबंटू पर मेरे जीसीसी 4.8.2 के साथ।

struct Node { 
    // some interface... 
private: 
    // doing this instead of depending on sizeof(Map) 
    char buffer[sizeof(std::unordered_map<std::string, void*>)]; 
    // other stuff... 
    void* dummy; 
}; 

struct Map { 
    // some interface... 
private: 
    // this is Map's only member 
    std::unordered_map<std::string, Node> map_; 
}; 

// and asserting this after the fact to make sure buffer is large enough 
static_assert (sizeof(Map) <= sizeof(std::unordered_map<std::string, void*>), 
    "Map is unexpectedly too large"); 
: (मैं इसे libstdc पर निर्भर करता है ++ संस्करण जीसीसी संस्करण की तुलना में अधिक पता है, लेकिन मैं आसानी से नहीं पता है कि खोजने के लिए कैसे ...)

एक विकल्प के रूप में, मैं निम्नलिखित तरीके को पर विचार कर रहा हूँ

यह मूल रूप से इस धारणा पर निर्भर करता है कि std::unordered_map<std::string, T> सभी टी के लिए समान आकार है, जो कि जीसीसी का उपयोग करके मेरे परीक्षण से सच है।

मेरा प्रश्न इस प्रकार तीन गुना है:

  • वहाँ सी ++ मानक में कुछ भी है की आवश्यकता है कि है कि यह धारणा सही पकड़ करने के लिए? (मुझे पता नहीं यह सोचते हैं हूँ, लेकिन अगर वहाँ मैं सुखद आश्चर्य होगा ...)

  • यदि नहीं, तो यह है व्यावहारिक रूप से सुरक्षित यह वैसे भी सभी उचित कार्यान्वयन के लिए सच है ग्रहण करने के लिए, और कहा कि स्थिर अभिकथन मेरे संशोधित संस्करण में कभी आग नहीं होगी?

  • अंत में, क्या इस मुद्दे पर कोई बेहतर कामकाज है जिसे मैंने नहीं सोचा है? मुझे यकीन है कि यह वहाँ स्पष्ट कुछ मैं बजाय कर सकते हैं कि मैं के बारे में सोचा नहीं किया है, लेकिन दुर्भाग्य से मैं कुछ भी नहीं सोच सकते हैं संभव है हूँ ...

+0

टिप्पणियां विस्तारित चर्चा के लिए नहीं हैं; यह वार्तालाप [चैट करने के लिए स्थानांतरित हो गया है] (http://chat.stackoverflow.com/rooms/77815/discussion-on-question-by-trantorian- व्यावहारिक रूप से-safe-to-assume-sizeofstdunor)। – Taryn

उत्तर

2

बस आगे बढ़ें और मान लें। फिर static_assert निर्माण पर आप सही हैं।

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

+0

मैंने इसे अभी स्वीकार कर लिया है क्योंकि आप एकमात्र व्यक्ति हैं जो मुझे अतिरिक्त संकेत का उपयोग नहीं करने के लिए कह रहे हैं (जो वास्तव में समस्या का हल नहीं है, बस इसे टालना है)। अगर आप रिकर्सिव डेटा स्ट्रक्चर पर विस्तृत कर सकते हैं, तो मैं उत्सुक हूं - हालांकि, मुझे लगता है कि यह पारस्परिक रूप से निर्भर प्रकारों के साथ संरचनाओं की अनुमति देने के लिए स्थगित टेम्पलेट नाम बाध्यकारी का लाभ लेने का कोई तरीका है? – Trantorian

+0

@ट्रान कैसे वैकल्पिक काम करता है। टेम्पलेट जानता है कि कुछ टैग खुद को संदर्भित करता है। – Yakk

+0

ठीक है, धन्यवाद, मुझे लगता है कि मुझे विचार मिलता है।हो सकता है कि ऐसा कुछ मदद करेगा - मैं अब के लिए 'static_assert' संस्करण रखूंगा और पृष्ठभूमि में एक विकल्प के रूप में ऐसा कुछ सोचूंगा – Trantorian

1

1) कोई

2) मैं मुझे यकीन नहीं है

3) आप डिजाइन पैटर्न फैक्टरी विधि का भी उपयोग कर सकते हैं। आपका कारखाना Map संस्करण के आधार पर ऑब्जेक्ट लौटाएगा (संपादित करें: मेरा मतलब है कि आप मानचित्र संस्करण उदाहरण का उपयोग पैरामीटर के रूप में करेंगे और फैक्टरी विधि कार्यान्वयन उस जानकारी का उपयोग तदनुसार वापसी ऑब्जेक्ट बनाने के लिए करेगा) और यह आकार को सही करने के लिए बफर को प्रीलाकेट कर सकता है।

+0

क्या आप स्पष्टीकरण दे सकते हैं कि आप 3 के साथ क्या सुझाव दे रहे हैं? विशेष रूप से, मैं संशोधित संस्करण में जो कुछ भी करता हूं उससे पॉइंटर्स के माध्यम से अतिरिक्त संकेत नहीं चाहता (जो 'static_assert' गुजरता है) काम करता है। 'नोड 'प्रभावी रूप से एक संघ है जिसमें बिना किसी प्रकार के एक प्रकार के संकेत होते हैं, और संभावित प्रकारों की सूची में' मानचित्र ',' std :: string', और' bool' शामिल है। – Trantorian

+0

आपके 'नोड' उदाहरण में से एक जीवनकाल में एक प्रकार का काम करेगा या यह अलग-अलग होगा? और क्या आप डिजाइन पैटर्न से परिचित हैं? –

+0

मेरे पास एक समय में केवल एक ही प्रकार होगा, लेकिन यह बदल सकता है। यदि प्रकार बदल दिया गया है, तो 'नोड' स्पष्ट रूप से वर्तमान सामग्री और प्लेसमेंट पर सही प्रकार के विनाशक को कॉल करेगा-नई प्रक्रिया का नया ऑब्जेक्ट, प्रक्रिया में एक प्रकार टैग अपडेट करना।मैं डिज़ाइन पैटर्न से परिचित हूं लेकिन यह नहीं देखता कि आपका क्या मतलब है - विशेष रूप से, ऐसा लगता है कि आप सुझाव दे रहे हैं कि फैक्ट्री कुछ सामान्य सूचक प्रकार को वापस कर देगी, जैसे 'शून्य *' के आकार के आधार पर 'नोड' से बचने के लिए 'Map'; यह वही है जो मैं नहीं चाहता क्योंकि अतिरिक्त संकेत तेजी से बढ़ जाएगा क्योंकि यह एक पुनरावर्ती संरचना है। – Trantorian

3

1) कोई

2) एसटीएल कंटेनर एक अधूरी प्रकार के साथ instantiated नहीं किया जा सकता है।हालांकि, जाहिर है कि कुछ कंपाइलर्स इसे अनुमति देते हैं। यह अनुमति नहीं दे रहा था कि यह एक मामूली निर्णय नहीं था और कई मामलों में आपकी धारणा वास्तव में सच रहेगी। This लेख आपको रूचि दे सकता है। इस तथ्य को देखते हुए कि मानक के अनुसार यह समस्या संकेत की परत जोड़ने के बिना हल नहीं हो सकती है और आप ऐसा नहीं करना चाहते हैं। मुझे सिर्फ एक सिर देना है, आप वास्तव में मानक के अनुसार चीजें नहीं कर रहे हैं।

ऐसा कहकर, मुझे लगता है कि आपका समाधान एसएलएल कंटेनर का उपयोग कर सबसे अच्छा है। और स्थिर जोर वास्तव में चेतावनी देगा जब आकार वास्तव में अपेक्षित आकार से अधिक हो जाता है।

3) हाँ अविवेक की एक और परत जोड़ने के साथ, मेरे समाधान निम्न होगा:

समस्या आप हैं, वे एक वस्तु का आकार, अपने सरणियों के आकार पर निर्भर करता है। बी के आकार के लिए घर वर्ण के क्रम में,

struct A 
{ 
    char sizeof[B] 
} 

struct B 
{ 
    char sizeof[A] 
} 

वस्तु एक बड़ा हो जाएगा लेकिन फिर बारी वस्तु बी में विकसित करने के लिए करना होगा: आप एक वस्तु एक और और वस्तु बी है कहो। मुझे लगता है कि आप देख सकते हैं कि यह कहां जा रहा है। मुझे पता है कि यह आपकी सही समस्या है, लेकिन मुझे लगता है कि अंतर्निहित सिद्धांत बहुत समान हैं।

char* buffer 

और गतिशील रूप से प्रारंभ करने के बाद स्मृति को आबंटित:

इस विशेष मामले में मैं इसे बदलने

char buffer[sizeof(Map)]; 

लाइन सिर्फ एक सूचक होने के लिए द्वारा हल होगा। अपने cpp फ़ाइल बोना कुछ इस तरह दिखेगा:

//node.cpp 
//untested code 
node::node() 
{ 
    buffer = malloc(sizeof(map)); 
} 

node::~node() 
{ 
    free buffer; 
} 
+0

नहीं, 'मानचित्र' में 'std :: unordered_map ', 'नोड' नहीं है, और पूर्व वास्तव में 'नोड' के आकार के साथ नहीं बढ़ता है, इसलिए यह मामला पसंद नहीं है मामला आप कह रहे हैं। व्यावहारिक रूप से, 'std :: unordered_map ' वास्तव में आकार को 'नोड' परिवर्तन के रूप में नहीं बदलता है, क्योंकि इसमें सीधे 'नोड' नहीं होता है; 'value_type' पैरामीटर के आधार पर आकार बदलने के लिए कोई भी कार्यान्वयन कुछ अजीब अनुकूलन करना चाहिए जो मैं अभ्यास में _practically_ से बाहर निकलने का प्रयास कर रहा हूं। – Trantorian

+0

इसके अलावा, मैं गतिशील रूप से स्मृति को आवंटित नहीं करना चाहता जैसे आप कह रहे हैं, क्योंकि यह संकेत की एक अतिरिक्त परत जोड़ता है। अधिक स्पष्टीकरण के लिए प्रश्न पर टिप्पणियों में चर्चा देखें। – Trantorian

+0

@ ट्राटोरियन आधिकारिक तौर पर किसी प्रकार के साथ किए गए किसी विशेष विशेषज्ञता के लिए, एक पूर्ण प्रकार की आवश्यकता होती है। यह सच हो सकता है कि 'unordered_map' वास्तव में आकार बदल नहीं है। लेकिन मैं अभी भी वहां नहीं जाऊंगा। मतलब है कि आपको पूर्ण प्रकार के बिना कक्षा को लागू करना होगा। यह केवल सी ++ की आवश्यकता है, आप एक दूसरे के पूर्ण प्रकार पर निर्भर दो वर्गों की घोषणा नहीं कर सकते हैं। मुझे डर है कि जहां तक ​​मुझे पता है, इस पर घूमने का एकमात्र तरीका है, वास्तव में संकेत की एक और परत जोड़ रहा है। – laurisvr

1

1) शायद नहीं

2) के बाद से ऐसा लगता है कि यह पूरी तरह से कार्यान्वयन पर निर्भर है, कि इस के रूप में एक बड़ा जोखिम सचमुच किसी भी संकलक अद्यतन में तोड़ सकते हैं है ।

3) आप boost::unordered_map का उपयोग कर सकते हैं जो अपूर्ण प्रकार स्वीकार करेगा और इस प्रकार आपकी समस्या का समाधान करेगा।

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