2016-04-02 22 views
10

मान लीजिए कि आप प्रकार std::vector<std::string> के एक चर है और आप एक प्रारंभकर्ता सूची के साथ यह प्रारंभ करते हैं:प्रारंभकर्ता_सूची के तत्वों को कैसे स्थानांतरित करें?

using V = std::vector<std::string>; 
V v = { "Hello", "little", "world", "of", "move", "semantics" }; 

संकलक प्रत्येक स्ट्रिंग शाब्दिक के लिए एक अस्थायी std::string पैदा करेगा, इन पर एक प्रारंभकर्ता सूची बनाने और उसके बाद ctor फोन V के लिए और वेक्टर बनाएं। सीटीओआर को पता नहीं है कि ये सभी तार अस्थायी हैं, इसलिए प्रत्येक स्ट्रिंग कॉपी कर रहा है।

मुझे मानक में कुछ भी नहीं मिला है जो वेक्टर सीटर को अस्थायी होने पर तत्वों को स्थानांतरित करने की अनुमति देता है।

क्या मुझे कुछ याद आ रहा है या प्रारंभकर्ता सूचियों का उपयोग करके अनावश्यक प्रतियों का कारण बनता है? मैं कक्षाएं लिख रहा हूं जहां यह समस्या महत्वपूर्ण अक्षम कोड का कारण बन सकती है। अनावश्यक प्रतियों से बचने के लिए कोई भी तकनीक की सराहना की जाएगी।

+0

अच्छा प्रश्न है। मुझे नहीं लगता कि प्रारंभकर्ता सूची मूल रूप से * इरादा * कुछ भी करने के लिए थीं लेकिन आसपास के अस्थायी लोगों के अनुक्रम को पास करती थीं। लेकिन अब आप एक प्रारंभकर्ता सूची चर घोषित कर सकते हैं। यह एक लंबे समय तक रहने वाली सूची में प्रत्येक आइटम से बाहर निकलने के लिए एक वेक्टर के लिए नहीं होगा। लेकिन प्रतीक्षा करें, प्रारंभिक सूची में रैवल्यू रेफरी के साथ निर्माता। शायद? –

+0

@ चीयर्संधथ.-एल्फ मुझे लगता है कि मैं कॉन्स्ट-रेफ, गैर-कॉन्स्ट-रेफ और रावल्यू-रेफ द्वारा प्रारंभिक सूची में ओवरलोड कर सकता हूं। मैं तत्वों को मैन्युअल रूप से रैवल्यू-रेफरी प्रारंभकर्ता सूची से स्थानांतरित कर सकता हूं। सुरुचिपूर्ण नहीं है और एसटीएल कंटेनरों के साथ काम नहीं करता है जो मैं वर्तमान में अंतर्निहित भंडारण (वेक्टर और मानचित्र) के रूप में उपयोग कर रहा हूं लेकिन कुछ भी नहीं। धन्यवाद। –

+0

[प्रारंभकर्ता \ _list और सैमसंगिक्स को स्थानांतरित करें] का डुप्लिकेट (https://stackoverflow.com/questions/8193102/initializer-list-and-move-semantics) –

उत्तर

4

वहाँ कोई रास्ता नहीं एक initializer_list<string> से नकल से बचने के लिए, क्योंकि मानक, एक निर्माता एक प्रारंभकर्ता सूची तर्क लेने के आह्वान को परिभाषित करता है वास्तविक तर्क के रूप में एक घुंघराले ब्रेसिज़ प्रारंभकर्ता से, इस प्रकार है (जोर जोड़ा) है:

सी ++ 14 §8.5.4/5

प्रकार std::initializer_list<E> की एक वस्तु एक प्रारंभकर्ता सूची से निर्माण किया है के रूप में अगर कार्यान्वयन प्रकार की N तत्वों की एक अस्थायी सरणी आवंटित, जहां N प्रारंभकर्ता सूची में तत्वों

IMHO की संख्या है यह वास्तव में दुर्भाग्यपूर्ण है।

एक वर्कअराउंड (अपनी कक्षाओं के लिए) initializer_list<char const*> स्वीकार करना है।


यहाँ वैकल्पिक हल std::vector<string> के लिए आवेदन किया, इसका एक उदाहरण। इसके लिए, जहां आप कक्षा कोड को नियंत्रित नहीं करते हैं, इसमें स्पष्ट रूप से एक डेटा सरणी (वास्तव में एक) घोषित करना शामिल है। यह सिर्फ सी ++ 03 है, जो प्रारंभकर्ता सूची तंत्र से बचने के लिए इरादा था के साथ है:

#include <vector> 
#include <initializer_list> 
#include <iostream> 
#include <iterator>    // std::begin, std::end 
using namespace std; 

struct My_string 
{ 
    char const* const ps; 

    My_string(char const* const s) 
     : ps(s) 
    { 
     cout << " My_string(*) <- '" << s << "'" << endl; 
    } 

    My_string(My_string const& other) 
     : ps(other.ps) 
    { 
     cout << " My_string(const&) <- '" << other.ps << "'" << endl; 
    }; 

    My_string(My_string&& other) 
     : ps(other.ps) 
    { 
     cout << " My_string(&&) <- '" << other.ps << "'" << endl; 
    }; 
}; 

auto main() -> int 
{ 
    cout << "Making vector a." << endl; 
    vector<My_string> const a = {"a1", "a2", "a3"}; 
    cout << "Making data for vector b." << endl; 
    auto const b_data   = { "b1", "b2", "b3" }; 
    cout << "Making vector b." << endl; 
    vector<My_string> const b(begin(b_data), end(b_data)); 
} 

आउटपुट:

 
Making vector a. 
    My_string(*) <- 'a1' 
    My_string(*) <- 'a2' 
    My_string(*) <- 'a3' 
    My_string(const&) <- 'a1' 
    My_string(const&) <- 'a2' 
    My_string(const&) <- 'a3' 
Making data for vector b. 
Making vector b. 
    My_string(*) <- 'b1' 
    My_string(*) <- 'b2' 
    My_string(*) <- 'b3' 
+0

आप एक विविध टेम्पलेट कन्स्ट्रक्टर का भी उपयोग कर सकते हैं। – o11c

+0

'कॉन्स ई'? धन्यवाद * वास्तव में * दुर्भाग्यपूर्ण है। इस के लिए कोई कारण है? अन्यथा, एक रैल्यू प्रारंभकर्ता सूची का पता लगाने से मुझे कम से कम मैन्युअल रूप से स्थानांतरित करने की अनुमति मिलेगी, लेकिन 'कॉन्स ई' के साथ, यह अवैध लगता है !? (और मैं वास्तव में 'std :: string' का उपयोग नहीं कर रहा हूं, मैं एक प्रकार का उपयोग कर रहा हूं जिसे मैंने लिखा है) कॉपी करने के लिए और अधिक महंगा हो सकता है) –

+0

मुझे लगता है कि मुझे' mutable' का उपयोग करके समाधान मिला, मैंने एक स्व-उत्तर जोड़ा। आपने इस बारे में क्या सोचा? –

2

कुछ सोच के बाद, मैं एक समाधान mutable के आधार पर साथ आया था। दूसरा उत्तर अभी भी अधिकतर सही है, लेकिन कोई शीर्ष-स्तर const -ness से छुटकारा पाने के लिए एक उत्परिवर्तनीय सदस्य के साथ प्रॉक्सी बना सकता है और उसके बाद तत्वों को वहां से ले जा सकता है। इसलिए प्रारंभकर्ता सूची लेने के तरीके को कॉन्स्ट-रेफरी प्रारंभकर्ता सूची और एक रैल्यू-रेफ संस्करण के लिए ओवरलोड करना चाहिए ताकि यह पता चल सके कि उन्हें कब स्थानांतरित करने की अनुमति है।

यहां एक कामकाजी उदाहरण है, यह पहले मनमाने ढंग से दिख सकता है लेकिन मेरे असली दुनिया के उपयोग-मामले में, इसने समस्या हल की।

#include <iostream> 
#include <vector> 

// to show which operations are called 
struct my_string 
{ 
    const char* s_; 
    my_string(const char* s) : s_(s) { std::cout << "my_string(const char*) " << s_ << std::endl; } 
    my_string(const my_string& m) : s_(m.s_) { std::cout << "my_string(const my_string&) " << s_ << std::endl; } 
    my_string(my_string&& m) noexcept : s_(m.s_) { std::cout << "my_string(my_string&&) " << s_ << std::endl; } 
    ~my_string() { std::cout << "~my_string() " << s_ << std::endl; } 
}; 

// the proxy 
struct my_string_proxy 
{ 
    mutable my_string s_; 

    // add all ctors needed to initialize my_string 
    my_string_proxy(const char* s) : s_(s) {} 
}; 

// functions/methods should be overloaded 
// for the initializer list versions 

void insert(std::vector<my_string>& v, const std::initializer_list<my_string_proxy>& il) 
{ 
    for(auto& e : il) { 
     v.push_back(e.s_); 
    } 
} 

void insert(std::vector<my_string>& v, std::initializer_list<my_string_proxy>&& il) 
{ 
    for(auto& e : il) { 
     v.push_back(std::move(e.s_)); 
    } 
} 

int main() 
{ 
    std::vector<my_string> words; 
    insert(words, { {"Hello"}, {"initializer"}, {"with"}, {"move"}, {"support"} }); 
} 

Live example

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