सी ++/सीएलआई में, स्ट्रिंग्स की सरणी को देशी चार ** में बदलने का सबसे प्रभावी तरीका क्या है?

मैं यह कर रहा हूँ:

array<String^>^ tokenArray = gcnew array<String^> {"TokenONE", "TokenTWO"};
int numTokens = tokenArray->Length;
char** ptr = new char* [numTokens];
for(int i = 0; i < numTokens; i++)
    {
        // See: http://stackoverflow.com/questions/6596242/
        array<Byte>^ encodedBytes = Text::Encoding::UTF8->GetBytes(tokenArray[i]);
        pin_ptr<Byte> pinnedBytes = &encodedBytes[0];
        ptr[i] = reinterpret_cast<char*>(pinnedBytes);
    }
int myResult = someNativeFunction(ptr, numTokens);
delete ptr;
// ...

क्या होगा, अगर कुछ सुधार किया जाना चाहिए? क्या यह स्मृति प्रबंधन के दृष्टिकोण से ठीक है? जरूरत पड़ने पर मैं someNativeFunction के मापदंडों को बदल सकता हूं।

धन्यवाद।

4
OG Dude 25 अगस्त 2011, 17:14
3
"क्या सुधार किया जा सकता है" - शायद मैन्युअल मेमोरी प्रबंधन और पॉइंटर्स का उपयोग बिल्कुल न करें और इसके बजाय मूल पक्ष पर std::strings का उपयोग करें।
 – 
Kerrek SB
25 अगस्त 2011, 17:17
5
एक बड़ी समस्या यह है कि आपके pin_ptr उपयोग करने से पहले आपके दायरे से बाहर हो जाते हैं।
 – 
Dark Falcon
25 अगस्त 2011, 17:21
मैं थोड़ा उलझन में हूं कि आपको टोकनएरे की आवश्यकता क्यों है। चूंकि आप इसका उपयोग नहीं कर रहे हैं, क्यों न केवल पीटीआर को सीधे सी-स्टाइल स्ट्रिंग्स पर इंगित करें? भले ही आप इसका उपयोग कर रहे हों, क्योंकि यह गतिशील नहीं लगता है, और छोटा है, फिर भी आप अलग से ptr क्यों नहीं बनाएंगे?
 – 
Ed Bayiates
25 अगस्त 2011, 22:12
DarkFalcon ने जो कहा है उसे दोहराने के लिए, आप someNativeFunction पॉइंटर्स को अप्रारंभीकृत मेमोरी में पास कर रहे हैं, जिसके परिणामस्वरूप स्मृति भ्रष्टाचार होगा।
 – 
ildjarn
25 अगस्त 2011, 22:52
1
: नहीं, यह कुछ भी नहीं बदलता है -- आपके pin_ptr, उनकी सामग्री को अनपिन करते हुए, for लूप के प्रत्येक पुनरावृत्ति के दायरे से बाहर हो जाते हैं, इसलिए जब तक आप प्रत्येक someNativeFunction को कॉल करते हैं ptr का तत्व यादृच्छिक डेटा की ओर इशारा कर रहा है।
 – 
ildjarn
26 अगस्त 2011, 21:30

1 उत्तर

सबसे बढ़िया उत्तर

someNativeFunction() को पास किए जाने से पहले पिन किए गए पॉइंटर्स के दायरे से बाहर जाने की समस्या के अलावा, कोड को बेहतर स्पष्टता के लिए सरल बनाया जा सकता है, खासकर यदि आप MSVC2008 या नए का उपयोग कर रहे हैं। एकल स्ट्रिंग को कैसे परिवर्तित किया जाए, इस बारे में जानकारी के लिए यह पृष्ठ देखें (सरणी तक विस्तार करना तुच्छ होना चाहिए) .

संपादित:

यदि आपको एएनएसआई स्ट्रिंग्स const char* की आवश्यकता है तो एक प्रतिलिपि बनाना अनिवार्य है क्योंकि .NET स्ट्रिंग्स यूनिकोड (यूटीएफ -16) हैं। MSVC2008 और नए पर, आपका कोड इस प्रकार दिख सकता है:

#include <msclr/marshal.h>
using namespace msclr::interop;

marshal_context context;
array<String^>^ tokenArray = gcnew array<String^> {"TokenONE", "TokenTWO"};
char** tokensAsAnsi = new char* [tokenArray->Length];

for(int i = 0; i < tokenArray->Length; i++)
{
    tokensAsAnsi[i] = context.marshal_as<const char*>(tokenArray[i]);
}
int myResult = someNativeFunction(ptr, tokensAsAnsi);

// The marshalled results are freed when context goes out of scope
delete[] tokensAsAnsi;    // Please note you must use delete[] here!

यह आपके कोड नमूने के समान काम करता है लेकिन पॉइंटर पिनिंग और reinterpret_cast-इंग की आवश्यकता के बिना।

यदि आप someNativeFunction() में विस्तृत स्ट्रिंग const wchar_t* से निपटने के इच्छुक हैं, तो आप सीधे (पिन किए गए) आंतरिक डेटा का उपयोग कर सकते हैं, हालांकि, आपको यह सुनिश्चित करना होगा कि someNativeFunction() तक पॉइंटर्स पिन किए रहें। रिटर्न, जैसा कि टिप्पणियों में बताया गया है, जीसी प्रदर्शन को नकारात्मक रूप से प्रभावित कर सकता है।

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

#2 संपादित:

यूटीएफ -8 एन्कोडिंग में मूल स्ट्रिंग प्राप्त करने के लिए, आप अपने कोड के संशोधित संस्करण के साथ कर सकते हैं:

array<String^>^ tokenArray = gcnew array<String^> {"TokenONE", "TokenTWO"};
char** tokensAsUtf8 = new char* [tokenArray->Length];

for(int i = 0; i < tokenArray->Length; i++)
{
    array<Byte>^ encodedBytes = Text::Encoding::UTF8->GetBytes(tokenArray[i]);

    // Probably just using [0] is fine here
    pin_ptr<Byte> pinnedBytes = &encodedBytes[encodedBytes->GetLowerBound(0)];

    tokensAsUtf8[i] = new char[encodedBytes->Length + 1]; 
    memcpy(
        tokensAsUtf8[i], 
        reinterpret_cast<char*>(pinnedBytes),
        encodedBytes->Length
        );

    // NULL-terminate the native string
    tokensAsUtf8[i][encodedBytes->Length] = '\0'; 

}
int myResult = someNativeFunction(ptr, tokensAsAnsi);

for(int i = 0; i < tokenArray->Length; i++) delete[] tokensAsUtf8[i];
delete[] tokensAsUtf8;    

यदि आप गति के बारे में चिंतित हैं, तो आप मूल स्ट्रिंग के लिए एक बड़ा बफर पूर्व-आवंटित कर सकते हैं (यदि आप जानते हैं कि केवल सीमित मात्रा होगी) या पूल स्टोरेज का उपयोग करें।

संपादित #3:(OG दोस्त) बस कुछ मामूली टाइपो को ठीक किया।

4
OG Dude 1 सितंबर 2011, 18:42
1
gcnew marshal_context क्रिंग-प्रेरक है -- स्टैक सेमेन्टिक्स का उपयोग करें और कोई delete आवश्यक नहीं है।
 – 
ildjarn
26 अगस्त 2011, 00:31
@ildjarn: यह सच है। मैंने अभी इसे सहायता पृष्ठ से कॉपी किया है।
 – 
Martin Gunia
26 अगस्त 2011, 11:41
1
: डेटा पिन करने की तुलना में मार्शलिंग सस्ता है या अधिक महंगा है या नहीं यह आपके आवेदन की समग्र आवंटन दर पर निर्भर करता है; प्रबंधित वस्तुओं को पिन करना जीसी में गंभीर रूप से बाधा डाल सकता है यदि पहले से ही बहुत अधिक आवंटन मंथन है, इसलिए कुछ परिदृश्यों में मार्शलिंग वास्तव में सस्ता है।
 – 
ildjarn
26 अगस्त 2011, 21:32
1
हां, यदि आप चाहते हैं कि const char* स्ट्रिंग UTF-8 एन्कोडेड हो तो आपका रास्ता ठीक है। आपको या तो वर्णों को किसी अन्य बफर में कॉपी करना होगा या डेटा को पिन करना होगा (उदाहरण के लिए पिन किए गए पॉइंटर्स को कंटेनर में डालकर) जब तक आप उनके साथ समाप्त नहीं कर लेते।
 – 
Martin Gunia
29 अगस्त 2011, 14:43
1
हां, मैं यही करता हूं, पॉइंटर्स को केवल memcpy-ed तक बफर के लिए पिन करना। जुड़ा हुआ एट्रिकल दूसरी दिशा से संबंधित है लेकिन आप केवल memcpy तर्कों को स्वैप कर सकते हैं, वैसे भी वे दोनों मूल बफर हैं। मैंने उत्तर में कोड जोड़ा है।
 – 
Martin Gunia
31 अगस्त 2011, 17:09