2012-06-26 20 views
22

के रूप में देखें सी सी शैली सरणी को एक std :: सरणी के रूप में किसी नए std :: array में कॉपी किए बिना कोई सुरक्षित और मानक अनुपालन तरीका है?सी सीस्टाइल सरणी को std :: array

यह स्पष्ट रूप से संकलित नहीं करता है, लेकिन यह प्रभाव मुझे पसंद है (मेरा असली उपयोग अधिक जटिल है लेकिन यह छोटा नमूना दिखाना चाहिए कि मैं क्या करना चाहता हूं)। मुझे लगता है कि एक reinterpret_cast "काम" होगा लेकिन शायद सुरक्षित नहीं है?

#include <array> 

int main() 
{ 
    int data[] = {1, 2, 3, 4, 5}; 

    // This next line is the important one, treating an existing array as a std::array 
    std::array<int, 5>& a = data; 
} 

ऐसा लगता है जैसे डेटा को समान रूप से संग्रहीत किया जाना चाहिए।

संपादित करें: स्पष्ट होने के लिए मैं एक नया std :: सरणी साफ़ नहीं करना चाहता, मैं मौजूदा डेटा को एक के रूप में संदर्भित करना चाहता हूं।

+1

एसटीएल कंटेनर अपने स्वयं के स्मृति का प्रबंधन। आप एक सरणी नहीं बना सकते हैं और इसे किसी अन्य सरणी को प्रबंधित कर सकते हैं जिसे आपने कहीं और आवंटित किया है। – krammer

+2

यह देखते हुए कि 'std :: array' और 'std :: vector' अपनी स्मृति को प्रबंधित करने की अपेक्षा करते हैं, आपको यह सुनिश्चित करने के लिए' reinterpret_cast' का उपयोग करने के बारे में बहुत सावधान रहना चाहिए कि वे डेटा को आजमाएं और हटाएं जो नहीं है उनके नियंत्रण में। लेकिन वह तरफ ... 'memcpy' से डरो मत। यह सब के बाद, एक काफी कुशल दिनचर्या है। – Rook

+0

ठीक है धन्यवाद। मैं इसे सुरक्षित रूप से करना चाहता हूं, हैक नहीं करता, मैंने सोचा कि क्या यह संभव था :) – jcoder

उत्तर

8

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

+5

है जिसे मैं समझता हूं। मैं अपने स्वयं के डेटा के साथ एक नया std :: सरणी नहीं बनाना चाहता, मैं मौजूदा डेटा को संदर्भित करना चाहता हूं जैसे कि यह एक std :: array था क्योंकि वे एक ही लेआउट की संभावना है। यदि सुरक्षित रूप से ऐसा करना संभव है। मुझे यकीन है कि एक reinterpret_cast "हैक" "काम" करेगा ... – jcoder

+0

वैसे भी "क्षमा करें आप सुरक्षित रूप से ऐसा नहीं कर सकते" सवाल का एक अच्छा जवाब है, भले ही मुझे उम्मीद न हो। – jcoder

7

आप reinterpret_cast उपयोग कर सकते हैं, फिर भी ध्यान दें कि यह एक बदसूरत गंदा हैक है और आप अपने वास्तविक रिहाई कोड में कुछ इस तरह नहीं करना चाहिए:

std::array<int, 5> &a = reinterpret_cast<std::array<int, 5>&>(data); 

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

आप फिर भी बदसूरत गंदा हैक के लिए जाने के लिए, कम से कम एक संकलन समय आकार की जांच जोड़ने का निर्णय लेते हैं:

C_ASSERT(sizeof(a) == sizeof(data)); 

यह एसटीडी का आकार :: सरणी <> बंद हो जाता है के मामले में कोई त्रुटि उत्पन्न करेगा आपके सी सरणी के आकार से मेल खाता है (एसटीएल कार्यान्वयन में कुछ बदलावों के कारण)।

+0

हाँ, मुझे यह "काम" करने के लिए मिला। मैंने सोचा कि क्या कोई रास्ता था जो बदसूरत गंदा हैक नहीं था :) धन्यवाद – jcoder

+3

नाम 'reinterpret_cast' नाम जानबूझकर बदसूरत है कि एक बदसूरत हैक का उपयोग किया जा रहा है। – MSalters

+0

धन्यवाद, अच्छा जवाब। मैं एक गंदे हैक के साथ नहीं जाऊंगा। मेरे कोड में बस एक मामला था जहां मेरे पास एक निश्चित आकार का सरणी था, इसलिए मेरे कोड में std :: array का उपयोग करना चाहता था, लेकिन पुराना कोड जिसे मैं नहीं बदल सकता, मुझे एक सी स्टाइल सरणी मिली। मैं इसके लिए एक हैक नहीं करूँगा, लेकिन यह कुछ अच्छा और समर्थित करने में सक्षम होना अच्छा होगा। – jcoder

15

के रूप में इस पोस्ट Is std::array<T, S> guaranteed to be POD if T is POD?

std::array<int, N> में चर्चा की पॉड और इस तरह मानक लेआउट है। जहां तक ​​मैं मानक लेआउट आवश्यकताओं को समझता हूं, इसका मतलब है कि ऑब्जेक्ट का पॉइंटर पहले सदस्य को पॉइंटर के समान है। चूंकि std :: सरणी में कोई निजी/संरक्षित सदस्य नहीं हैं (http://en.cppreference.com/w/cpp/container/array के अनुसार), यह रैप किए गए सरणी में पहले तत्व से सहमत होना चाहिए। जैसे

reinterpret_cast< std::array<int, 5>* >(&data)

इस प्रकार कुछ मेरी राय मानक से कार्य करने की गारंटी है। मुझे यह मानना ​​है कि, मुझे कभी-कभी मानक भाषा की व्याख्या करने में कठिनाई होती है, इसलिए यदि मैं गलत हूं तो कृपया मुझे सही करें।

सादर Claas

+2

मुझे लगता है कि आप सही हैं लेकिन मैं array5 * p = reinterpret_cast < array5* > (& डेटा); एएसएसईआरटी (पी-> डेटा() == &data); जो हम आखिरकार चाहते हैं – GameDeveloper

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