2016-09-13 7 views
6

पर वेक्टर में कई unique_ptrs सम्मिलित करने के लिए मैं एक वेक्टर है:कैसे एक बार

std::vector<std::unique_ptr<int>> 

और एक निर्दिष्ट स्थान पर इसे में कई नए unique_ptr<int> के सम्मिलित करना चाहते हैं। सदस्य std::vector::insert(iterator position, size_type n, const value_type& val) कार्य करता है लेकिन हां, unique_ptr की प्रतिलिपि बनाने पर प्रतिबंध इस अधिभार के उपयोग की अनुमति नहीं देते हैं।

मैंने this question पढ़ा है, हालांकि यह unique_ptr है जो पहले से ही किसी अन्य वेक्टर में मौजूद है। मैं नए बनाना चाहता हूं।

मुझे पता है मैं एक पाश के साथ यह कर सकते हैं, उदाहरण के वेक्टर की शुरुआत करने के लिए 3 नए आइटम को सम्मिलित करने के लिए:

for (int n = 0; n != 3; ++n) 
    vec.insert(vec.begin(), std::make_unique<int>(0)); 

हालांकि मैं हो, तो यह करने के लिए एक क्लीनर तरीका सोच रहा हूँ, और संभवतः एक जो नई मेमोरी अप-फ्रंट आवंटित करता है।

स्पष्टीकरण के लिए संपादित करें: वेक्टर में जोड़ने के लिए आइटमों की संख्या पूरी तरह से मनमानी है - मैंने अपने उदाहरण कोड में 3 लिखा है लेकिन यह कोई मूल्य हो सकता है और यह आवश्यक नहीं है कि संकलन समय पर जाना जाता है।

+6

के बाद से आप प्रत्येक 'std :: unique_ptr' के लिए एक अलग' int' आवंटित करने के लिए की जरूरत है, कोई क्लीनर तरीका से बचने के लिए एक पाश का उपयोग किए बिना ऐसा करने के लिए जो 'std :: make_unique() ', या पॉइंटर्स के किसी अन्य सरणी/कंटेनर से आगे बढ़ता है। अन्यथा, अपने डिजाइन को फिर से सोचें। उदाहरण के लिए, हो सकता है कि 3 तत्वों के साथ एक एकल 'std :: वेक्टर 'हो। या एक 'std :: unique_ptr ' 3-तत्व सरणी धारण करना, और उसके बाद एक अलग 'std :: वेक्टर ' उस सरणी में कच्चे पॉइंटर्स युक्त। –

+0

... या 'std :: generate_n ( std :: Inserter (vec, vec.begin()), 3, std :: बाँध (std :: make_unique , 0) );' लेकिन मैं wouldn साफ नहीं है। – jrok

उत्तर

1

आप संकलन समय कितने संकेत आप सदिश में डाल करना चाहते हैं पर जानते हैं, आप निम्न में से एक की तरह एक समारोह का उपयोग कर सकते हैं:

#include<vector> 
#include<memory> 
#include<cstddef> 

template<std::size_t... I> 
constexpr auto gen(std::index_sequence<I...>) { 
    std::vector<std::unique_ptr<int>> vec; 
    int arr[] = { (vec.push_back(std::make_unique<int>(0)), I)... }; 
    (void)arr; 
    return vec; 
} 

template<std::size_t N> 
constexpr auto create() { 
    return gen(std::make_index_sequence<N>{}); 
} 

int main() { 
    auto vec = create<3>(); 
} 
+0

वैकल्पिक, सरणी से बचने के लिए: '(vec.push_back (std :: make_unique (0 * I)), ...);' – bolov

1

वहाँ स्मृति के दो विभिन्न प्रकार यहाँ आवंटित किया जा रहा है। के लिए vector में आवंटित स्मृति है (जो बहुत अधिक नहीं होगी, प्रति अद्वितीय_इंटर प्रति पॉइंटर)। और फिर प्रत्येक unique_ptr द्वारा प्रबंधित ऑब्जेक्ट के लिए गतिशील रूप से आवंटित स्मृति।

आप सभी स्मृति सामने प्रत्येक unique_ptr भीतर वस्तु के लिए गतिशील रूप से आबंटित स्मृति के रूप में अलग से आवंटित किया जाना चाहिए आवंटित नहीं कर सकता।

लेकिन आप एक से अधिक insert कॉल आप एक आरक्षित पहले कर सकता है की वजह से वेक्टर के लिए स्मृति के reallocations से बचने के लिए चाहते हैं:

vec.reserve(vec.size() + n); 

मुझे शक है यह n के रूप में छोटे 3 के रूप में यद्यपि के लिए किसी भी प्रभाव पड़ेगा ।

अधिक समस्या यह है कि प्रत्येक insert के लिए वेक्टर को vector की सभी सामग्री को एक साथ डालने के बाद स्थानांतरित करना होगा। unique_ptr स्थानांतरित करना सस्ता है लेकिन यह ऐड-अप हो सकता है।

यह निश्चित रूप से क्लीनर नहीं है, लेकिन आप std::move_backward का उपयोग कर अपने आप को आगे बढ़ सकते हैं।आकार के लिए आवश्यक करने के लिए वेक्टर आकार बदलें, साथ सभी तत्वों को स्थानांतरित और उसके बाद के लिए कदम-असाइन तत्वों में unique_ptr जहां आप सम्मिलित करना चाहते:

auto prev_size = vec.size(); 
vec.resize(prev_size + 3); 
auto prev_end = vec.begin() + prev_size; 
std::move_backward(vec.begin(), prev_end, vec.end()); 
for (int n = 0; n != 3; ++n) 
    vec[n] = std::make_unique<int>(0); 

एक और, शायद क्लीनर, एक ही बात को प्राप्त करने का रास्ता बनाने के लिए है अपने स्वयं के कस्टम आगे इटरेटर insert की std::vector::insert(const_iterator position, InputIterator first, InputIterator last); अधिभार में उपयोग करने के लिए:

template<typename T> 
struct UniquePtrInserter : std::iterator< 
          std::forward_iterator_tag, 
          std::unique_ptr<T>, 
          std::ptrdiff_t, 
          const std::unique_ptr<T>*, 
          std::unique_ptr<T>>{ 
    int n_; 
public: 
    explicit UniquePtrInserter<T>(int n = 0) : n_(n) {} 
    UniquePtrInserter<T>& operator++() {n_++; return *this;} 
    bool operator==(UniquePtrInserter<T> other) const {return n_ == other.n_;} 
    bool operator!=(UniquePtrInserter<T> other) const {return !(*this == other);} 
    std::unique_ptr<T> operator*() const {return std::make_unique<T>(); } 
}; 

vec.insert(vec.begin(), UniquePtrInserter<int>(0), UniquePtrInserter<int>(3)); 
0

यह करने के लिए स्पष्ट तरीका है एक कदम इटरेटर उपयोग करने के लिए उदाहरण के लिए, तत्व स्थानांतरित करने के लिए:

#include <iostream> 
#include <vector> 
#include <memory> 
#include <iterator> 

using T = std::unique_ptr<int>; 

void print_vec(const std::vector<T>& vec) 
{ 
    for (auto& x: vec) { 
     std::cout << ' ' << *x; 
    } 
    std::cout << '\n'; 
} 

template <typename V, typename ...X> 
void emplace(V& v, typename V::const_iterator i, X&&... x) { 
    T a[] = { std::forward<X>(x)... }; 
    v.insert(i, std::make_move_iterator(std::begin(a)), std::make_move_iterator(std::end(a))); 
} 

int main() 
{ 
    std::vector<T> vec; 
    emplace(vec, vec.begin(), std::make_unique<int>(601), std::make_unique<int>(602), std::make_unique<int>(603)); 
    print_vec(vec);  
    emplace(vec, std::next(vec.begin()), std::make_unique<int>(501), std::make_unique<int>(502), std::make_unique<int>(503)); 
    print_vec(vec); 

} 

मैंने एक साधारण रैपर फ़ंक्शन प्रदान किया है जो एक अनुक्रम (विविधता तर्क अनुक्रम के रूप में) लेता है और इसे move_iterator का उपयोग करके वेक्टर में सम्मिलित करता है।

लेकिन आप किसी भी कंटेनर से स्थानांतरित करने के लिए move_iterator का उपयोग कर सकते हैं जो चालक ऑपरेटर का समर्थन करेगा।

0

आप generate_n उपयोग कर सकते हैं कच्चे पाश

std::vector<std::unique_ptr<int>> vec; 
generate_n(back_inserter(vec), 3, []() { return make_unique<int>(); });