2012-07-02 6 views
9

मैं std :: स्ट्रिंग चार डेटा का स्वामित्व कैसे ले सकता हूं और स्रोत std :: string ऑब्जेक्ट को रखने के साथ? (मैं चलती शब्दावली का उपयोग करना चाहता हूं लेकिन विभिन्न प्रकारों के बीच।)मैं std :: string object को कॉपी और रखे बिना C++ std :: स्ट्रिंग चार डेटा का स्वामित्व कैसे ले सकता हूं?

मैं सी ++ 11 Clang कंपाइलर और Boost का उपयोग करता हूं।

मूल रूप से मैं इस के लिए कुछ बराबर करना चाहते हैं:

{ 
    std::string s(“Possibly very long user string”); 
    const char* mine = s.c_str(); 

    // 'mine' will be passed along, 
    pass(mine); 

    //Made-up call 
    s.release_data(); 

    // 's' should not release data, but it should properly destroy itself otherwise. 
} 

, स्पष्ट मैं क्या ज़रूरत है std :: स्ट्रिंग से छुटकारा पाने के लिए: आगे सड़क के नीचे। कोड स्ट्रिंग और बाइनरी डेटा दोनों से संबंधित है और इसे उसी प्रारूप में संभालना चाहिए। और मैं std :: स्ट्रिंग से डेटा चाहता हूं, क्योंकि यह एक और कोड परत से आता है जो std :: string के साथ काम करता है।

अधिक परिप्रेक्ष्य देने के लिए जहां मैं ऐसा करना चाहता हूं: उदाहरण के लिए मेरे पास एक एसिंक्रोनस सॉकेट रैपर है जो लिखने के लिए उपयोगकर्ता से std :: स्ट्रिंग और बाइनरी डेटा दोनों लेने में सक्षम होना चाहिए। दोनों "एपीआई" लिखने वाले संस्करण (std :: स्ट्रिंग या पंक्ति बाइनरी डेटा लेते हुए) आंतरिक रूप से उसी (बाइनरी) लिखने के लिए हल होते हैं। मुझे किसी भी प्रतिलिपि से बचने की आवश्यकता है क्योंकि स्ट्रिंग लंबे हो सकती है।

WriteId  write(std::unique_ptr<std::string> strToWrite) 
{ 

    // Convert std::string data to contiguous byte storage 
    // that will be further passed along to other 
    // functions (also with the moving semantics). 
    // strToWrite.c_str() would be a solution to my problem 
    // if I could tell strToWrite to simply give up its 
    // ownership. Is there a way? 

    unique_ptr<std::vector<char> > dataToWrite= ?? 

    // 
    scheduleWrite(dataToWrite); 
} 

void scheduledWrite(std::unique_ptr< std::vecor<char> > data) 
{ 
    … 
} 

std :: इस उदाहरण में unique_ptr स्वामित्व हस्तांतरण वर्णन करने के लिए: एक ही अर्थ विज्ञान के साथ किसी भी अन्य दृष्टिकोण मेरे लिए ठीक है।

मैं इस विशिष्ट मामले (std :: string char buffer के साथ) और तारों, धाराओं और इसी तरह के सामान्य के साथ इस तरह की समस्या के समाधान के बारे में सोच रहा हूं: स्ट्रिंग, स्ट्रीम, एसडीडी कंटेनर और बफर के बीच चलती बफर तक पहुंचने के लिए युक्तियाँ प्रकार के।

मैं सी ++ डिजाइन दृष्टिकोण और विशिष्ट तकनीकों के साथ युक्तियों और लिंक की भी सराहना करता हूं जब प्रतिलिपि के बिना विभिन्न एपीआई/प्रकारों के बीच बफर डेटा पास करने की बात आती है। मैं उल्लेख करता हूं लेकिन धाराओं का उपयोग नहीं करता क्योंकि मैं उस विषय पर अशक्त हूं।

+1

आप नहीं कर सकते हैं, कोई रास्ता नहीं है क्योंकि वहाँ आप को पुनः प्राप्त कर सकते हैं स्मृति सुरक्षित रूप से। एक बिंदु पर आपको बफर जारी करना चाहिए, तो स्ट्रिंग को सभी तरह से क्यों न रखें, यह स्वचालित रूप से कौन सा होता है? –

+0

आप अपने स्वयं के स्ट्रिंग कार्यान्वयन को बेहतर लिखते हैं – Gigi

+4

'std :: unique_ptr 'एकमात्र चीज होगी जो कुछ भी समान की अनुमति देती है। – ildjarn

उत्तर

9

मैं std :: स्ट्रिंग चार डेटा का स्वामित्व कैसे ले सकता हूं और स्रोत std :: string ऑब्जेक्ट को रखने के साथ? (मैं चलती शब्दावली का उपयोग करना चाहता हूं लेकिन विभिन्न प्रकारों के बीच)

आप इसे सुरक्षित रूप से नहीं कर सकते हैं।

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


आप कॉपी कर आप scheduledWrite के लिए इंटरफ़ेस को बदलने पर विचार कर सकता है से बचना चाहते हैं। एक संभावना कुछ है:

template<typename Container> 
void scheduledWrite(Container data) 
{ 
    // requires data[i], data.size(), and &data[n] == &data[0] + n for n [0,size) 
    … 
} 

// move resources from object owned by a unique_ptr 
WriteId write(std::unique_ptr< std::vector<char> > vecToWrite) 
{ 
    scheduleWrite(std::move(*vecToWrite)); 
} 

WriteId write(std::unique_ptr<std::string> strToWrite) 
{ 
    scheduleWrite(std::move(*strToWrite)); 
} 

// move resources from object passed by value (callers also have to take care to avoid copies) 
WriteId write(std::string strToWrite) 
{ 
    scheduleWrite(std::move(strToWrite)); 
} 

// assume ownership of raw pointer 
// requires data to have been allocated with new char[] 
WriteId write(char const *data,size_t size) // you could also accept an allocator or deallocation function and make ptr_adapter deal with it 
{ 
    struct ptr_adapter { 
     std::unique_ptr<char const []> ptr; 
     size_t m_size; 
     char const &operator[] (size_t i) { return ptr[i]; } 
     size_t size() { return m_size; } 
    }; 

    scheduleWrite(ptr_adapter{data,size}); 
} 
+1

@ मिंस्क: यह जानना काफी उचित है कि दुर्भाग्य से यह संभव नहीं है, क्योंकि कक्षा को इसे अनुमति देने के लिए डिज़ाइन नहीं किया गया है। –

+0

@ मिंस्क: आपको नहीं पता कि बफर को कैसे जारी किया जाना चाहिए। चूंकि कोई 'रिलीज' सदस्य नहीं है, इसलिए आप 'स्ट्रिंग' के साथ जो चाहते हैं उसे प्राप्त नहीं कर सकते हैं। –

+0

वे अच्छे अंक हैं: छोटे स्ट्रिंग अनुकूलन और अन्य कार्यान्वयन बफर को कैसे रिलीज़ करना है। Std :: stringstream के बारे में क्या, क्या मैं std :: स्ट्रिंग को std :: stringstream में ले जा सकता हूं जो इसके बफर का खुलासा करता है? वे दोनों std ऑब्जेक्ट्स हैं, और std :: स्ट्रिंगस्ट्रीम std :: स्ट्रिंग से अवगत है .. मैं वास्तव में एक समाधान ढूंढना चाहता हूं जो प्रतिलिपि से बचाता है और कोड के हिस्से को तारों के साथ काम करने की अनुमति देता है :( – minsk

1

आप इसे हल करने के लिए बहुरूपता का उपयोग कर सकते हैं। आधार प्रकार आपके एकीकृत डेटा बफर कार्यान्वयन के लिए इंटरफ़ेस है। फिर आपके पास दो व्युत्पन्न कक्षाएं होंगी। स्रोत के रूप में std::string के लिए एक, और दूसरा आपके डेटा प्रतिनिधित्व का उपयोग करता है।

struct MyData { 
    virtual void * data() = 0; 
    virtual const void * data() const = 0; 
    virtual unsigned len() const = 0; 
    virtual ~MyData() {} 
}; 

struct MyStringData : public MyData { 
    std::string data_src_; 
    //... 
}; 

struct MyBufferData : public MyData { 
    MyBuffer data_src_; 
    //... 
}; 
+0

उपयोगकर्ता315052 मैंने इस जवाब को चिह्नित किया क्योंकि यह उत्तर देने के लिए एक समाधान और थाक्स है। लेकिन मैं संभावित दृष्टिकोण वर्चुअल विरासत हिट सहित कई कारणों से इस दृष्टिकोण से बचूंगा, सुरक्षा टाइप करें, एमए सगाई के मुद्दों; यह सड़क के नीचे एक डेटा प्रकार (MyData) लगाता है। बहुत बोझिल हो सकता है। मुझे data_src_ के आस-पास कुछ प्रकार की अनूठी पहुंच प्राप्त करनी होगी, इसके शीर्ष पर मुझे नया माइडाटा करना होगा और उसे लपेटना होगा (इसे अन्य धागे सहित पास करने के लिए)। अगर मुझे एक रैपर के साथ जाना है, तो मैं वर्चुअल के बिना कम घुसपैठ और सुरक्षित दृष्टिकोण का उपयोग करूंगा, जिसे पहले जवाब में bames53 – minsk

2

एक स्ट्रिंग के इस वर्ग को ले स्वामित्व चाल अर्थ विज्ञान और shared_ptr का उपयोग कर:

struct charbuffer 
{ 
    charbuffer() 
    {} 

    charbuffer(size_t n, char c) 
    : _data(std::make_shared<std::string>(n, c)) 
    {} 

    explicit charbuffer(std::string&& str) 
    : _data(std::make_shared<std::string>(str)) 
    {} 

    charbuffer(const charbuffer& other) 
    : _data(other._data) 
    {} 

    charbuffer(charbuffer&& other) 
    { 
    swap(other); 
    } 

    charbuffer& operator=(charbuffer other) 
    { 
    swap(other); 
    return *this; 
    } 

    void swap(charbuffer& other) 
    { 
    using std::swap; 
    swap(_data, other._data); 
    } 

    char& operator[](int i) 
    { 
    return (*_data)[i]; 
    } 

    char operator[](int i) const 
    { 
    return (*_data)[i]; 
    } 

    size_t size() const 
    { 
    return _data->size(); 
    } 

    bool valid() const 
    { 
    return _data; 
    } 

private: 
    std::shared_ptr<std::string> _data; 

}; 

उदाहरण उपयोग:

std::string s("possibly very long user string"); 

charbuffer cb(std::move(s)); // s is empty now 

// use charbuffer... 
+0

द्वारा सुझाया गया है, जहां तक ​​मैं समझता हूं कि चारबफर वाले charbuffer को खाली खाली_प्टर (वही है जो एक ही है प्रतिलिपि प्रतिलिपि कन्स्ट्रक्टर में डिफॉल्ट बनाया गया था) इसलिए जब स्थानांतरित चारबफर गुंजाइश से बाहर निकलता है और इसके विनाशक को बुलाया जाता है तो कुछ भी नहीं होता है। – Gigi

+0

आप 100% सही हैं, यकीन नहीं है कि मैं अब क्या सोच रहा था। :- पी शोर के लिए खेद है। – ildjarn

+0

कोई समस्या नहीं है :) – Gigi

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