2016-03-01 10 views
10

निर्माण मैं इस किया है। हालांकि, प्रत्येक vector में आइटमों की संख्या ज्ञात नहीं है लेकिन मेरे पास इसके बारे में अनुमान है इसलिए मैं reservesub vectors पर वापस धक्का शुरू करने से पहले चाहता हूं। क्या मैं वर्तमान में कर रहा हूँ है:उप वैक्टर आरक्षण जबकि

size_t estimated_size = 1000; 
for (auto& sub_vector: v){ 
    sub_vector.reserve(estimated_size); 
} 

वहाँ एक बेहतर तरीका है? निर्माण करते समय इसे करने की तरह?

पीएस

size_t n = 100; 
size_t estimated_size = 1000; 
std::vector<std::vector<foo>> v(n, std::vector<foo>(estimated_size)); 

मैं सिर्फ इसलिए foo दो बार निर्माण करने costy है निर्माण के बिना आरक्षित करना चाहते हैं: यह एक विकल्प नहीं है।

+0

मैं इसे कैसे आप भीतरी वैक्टर पॉप्युलेट करने के लिए जा रहे हैं के बारे में ज्यादा निर्भर करता है लगता है। – LogicStuff

+0

@LogicStuff क्या आप थोड़ा सा स्पष्टीकरण दे सकते हैं? –

+0

"मैं बस निर्माण के बिना आरक्षित करना चाहता हूं क्योंकि फू दो बार निर्मित करने के लिए महंगा है।" - 'foo' को सीधे स्टोर न करें? शायद ['std :: unique_ptr '] (http://en.cppreference.com/w/cpp/memory/unique_ptr), या ['std :: प्रयोगात्मक :: वैकल्पिक '] (http: // en। cppreference.com/w/cpp/experimental/optional)। – BoBTFish

उत्तर

3

आप वास्तव में यह करने के लिए है, जबकि निर्माण चाहते हैं vector आप constructor कि दो iterators लेता है का उपयोग करें और अपने स्वयं के कस्टम इटरेटर प्रदान कर सकता है। इटरेटर अपसंदर्भन एक वेक्टर आरक्षित इसे बनाने और फिर इसे वापस:

class VectorReserveItr : public std::iterator<std::input_iterator_tag, foo> { 
    size_t i; 
    size_t capacity; 
public: 
    VectorReserveItr(size_t i, size_t capacity) : i(i), capacity(capacity) {} 
    VectorReserveItr& operator++() { ++i; return *this; } 
    bool operator!=(const VectorReserveItr& rhs) { return i != rhs.i; } 
    std::vector<foo> operator*() { 
     std::vector<foo> ret; 
     ret.reserve(capacity); 
     return ret; 
    } 
}; 

std::vector<std::vector<foo>> v(VectorReserveItr(0, 1000), VectorReserveItr(100, 1000)); 

लेकिन मैं इसे एक पाश की तुलना में तेजी होने की उम्मीद नहीं होता और मुझे नहीं लगता कि यह या तो अधिक पठनीय है।

template<class F, 
    class T=std::result_of_t<F const&(std::size_t const&)> 
> 
struct countdown_iterator: 
    std::iterator< 
    std::input_iterator_tag, 
    T, 
    std::ptrdiff_t, 
    T*, 
    T 
    > 
{ 
    using self=countdown_iterator; 
    std::size_t count_down = 0; 
    F f; 
    T operator*() const { 
    return f(count_down); 
    } 
    self& operator++() { 
    --count_down; 
    return *this; 
    } 
    self operator++(int) { 
    auto result = *this; 
    ++(*this); 
    return result; 
    } 
    friend bool operator==(self const& lhs, self const& rhs) { 
    return lhs.count_down == rhs.count_down; 
    } 
    friend bool operator!=(self const& lhs, self const& rhs) { 
    return !(lhs==rhs); 
    } 
}; 

एक आधा assed रेंज वर्ग:

template<class It> 
struct range { 
    It b, e; 
    It begin() const { return b; } 
    It end() const { return e; } 
    bool empty() const { return begin()==end(); } 
    decltype(auto) front() const { return *begin(); } 
    range():b(),e() {} 
    range(It s, It f):b(s), e(f) {} 
    range(range const&)=default; 
    range& operator=(range const&)=default; 
    ~range() = default; 

    template<class C, 
    class=std::enable_if_t<!std::is_same<std::decay_t<C>, range>> 
    > 
    range(C&& c): 
    range(std::begin(std::forward<C>(c)), std::end(std::forward<C>(c))) 
    {} 
}; 
template<class It> 
range<It> make_range(It b, It e) { return {std::move(b),std::move(e)}; }; 

और फिर हम भरोसा कर सकते हैं:

template<class F, 
    class dF=std::decay_t<F>, 
    class It=countdown_iterator<dF> 
    class R=range<It> 
> 
R countdown(std::size_t N, F&& f) { 
    countdown_iterator e(N, f): 
    countdown_iterator b(N, std::forward<F>(f)); 
    return {std::move(b),std::move(e)}; 
} 

Live demo.

2

यहां एक त्वरित उलटी गिनती इटरेटर है उपयोग :

size_t n = 100; 

size_t m = 1000; 
auto src = countdown(
    n, 
    [m](auto&&){ std::vector<foo> v; v.reserve(m); return v; } 
); 
std::vector<std::vector<foo>> v; 
v.reserve(100); 
v.insert(v.end(), src.begin(), src.end()); 

यहां हम एक उलटी गिनती "इनपुट" इटरेटर बनाते हैं जो 100 इटरेटर के लिए चलता है। हर बार जब आप इसे अस्वीकार करते हैं तो यह m क्षमता के साथ एक वेक्टर लौटाता है।

+1

क्यों नहीं 'एसटीडी भूल जाता है :: वेक्टर > v (src.begin(), src.end()); '? – Barry

+0

@barry संदर्भ समस्या के कारण यादृच्छिक एक्सेस इनपुट इटरेटर (बैकिंग स्टोर के बिना) नहीं लिख सकता है। तो वेक्टर को पूर्व आकार के ठीक से उम्मीद नहीं कर सकते हैं। तो हैवेन्टो मैन्युअल रूप से आरक्षित। सिम्प्की परिभाषित '-' कुछ कंपेलरों पर काम कर सकता है, वैसे ही मूल्य संदर्भ प्रकार होने के बावजूद यादृच्छिक पहुंच होने का दावा करता है, लेकिन मैं सतर्क हूं। – Yakk

1

Yakk's का पिग्गी-पैकिंग इस तरह से उत्तर देता है जिसमें वास्तव में अपना कोड लिखना शामिल नहीं होता है। Ranges-v3 के साथ, हम सही क्षमता के vector एस की एक श्रृंखला का निर्माण करके इसे सीधे कर सकते हैं। मैं यह भी पता यह बहुत आसान को पढ़ने के लिए:

std::vector<std::vector<int>> v = 
    view::ints(0, 100) 
    | view::transform([](int) { 
     std::vector<int> sub_v; 
     sub_v.reserve(100); 
     return sub_v; 
    }); 
संबंधित मुद्दे