2013-06-09 23 views
15

इस स्निपेट पर विचार करें:वेक्टर सामग्री को किसी अन्य वेक्टर में जोड़ने के लिए C++ 11 move semantics का उपयोग कैसे करें?

class X; 

void MoveAppend(vector<X>& src, vector<X>& dst) { 
    dst.reserve(dst.size() + src.size()); 
    for (const X& x : src) dst.push_back(x); 
    src.clear(); 
} 

अगर हम मान लेते हैं कि class X औजार अर्थ विज्ञान ले जाते हैं, मैं कैसे कुशलतापूर्वक MoveAppend लागू कर सकते हैं?

उत्तर

27

बस कार्य करें:

#include <iterator> 
#include <algorithm> 

// ... 

void MoveAppend(std::vector<X>& src, std::vector<X>& dst) 
{ 
    if (dst.empty()) 
    { 
     dst = std::move(src); 
    } 
    else 
    { 
     dst.reserve(dst.size() + src.size()); 
     std::move(std::begin(src), std::end(src), std::back_inserter(dst)); 
     src.clear(); 
    } 
} 

तो dst खाली है, srcdst करने से एक कदम-असाइनमेंट काम करेगा - कि के रूप में सस्ते के रूप में यह हो सकता है हो जाएगा, बस सरणी द्वारा समझाया "चोरी" src ताकि dst इसे बाद में इंगित करेगा।

यदि dst खाली नहीं है, तो dst पर जोड़े गए तत्व src में तत्वों से स्थानांतरित किए जाएंगे। std::move() पर कॉल करने के बाद, src खाली नहीं होगा - इसमें तत्वों से "ज़ोंबी" स्थानांतरित होगा। यही कारण है कि clear() पर कॉल अभी भी जरूरी है।

+1

डीएसटी खाली नहीं है। –

+0

@ ŁukaszLew: ठीक है, जो चीजों को बदलता है। मैं –

+0

@ ŁukaszLew संपादित करूंगा: मैंने जवाब बदल दिया। गलतफहमी के लिए खेद है –

11

मैं थोड़ा स्वीकार किए जाते हैं जवाब देने के लिए इस पसंद करेंगे:

#include <vector> 
#include <iterator> 
#include <utility> 

template <typename T> 
typename std::vector<T>::iterator append(const std::vector<T>& src, std::vector<T>& dest) 
{ 
    typename std::vector<T>::iterator result; 

    if (dest.empty()) { 
     dest = src; 
     result = std::begin(dest); 
    } else { 
     result = dest.insert(std::end(dest), std::cbegin(src), std::cend(src)); 
    } 

    return result; 
} 

template <typename T> 
typename std::vector<T>::iterator append(std::vector<T>&& src, std::vector<T>& dest) 
{ 
    typename std::vector<T>::iterator result; 

    if (dest.empty()) { 
     dest = std::move(src); 
     result = std::begin(dest); 
    } else { 
     result = dest.insert(std::end(dest), 
          std::make_move_iterator(std::begin(src)), 
          std::make_move_iterator(std::end(src))); 
    } 

    src.clear(); 
    src.shrink_to_fit(); 

    return result; 
} 

उदाहरण:

#include <string> 
#include <algorithm> 
#include <iostream> 

int main() 
{ 
    const std::vector<std::string> v1 {"world", "!"}; 

    std::vector<std::string> v2 {" "}, v3 {"hello"}, v4 {}; 

    append(v1, v2); // copies 
    append(std::move(v2), v3); // moves 
    append(std::move(v3), v4); // moves 

    std::copy(std::cbegin(v4), std::cend(v4), std::ostream_iterator<std::string> {std::cout}); 
    std::cout << std::endl; 
} 
+0

मुझे लगता है कि यह एक बेहतर उत्तर है, इसमें लवल और रावल्यू स्रोत के लिए अधिभार है, और std :: vector :: insert() का उपयोग करता है। – dats

+2

आप रावल्यू स्रोत क्यों "साफ" करते हैं? मुझे लगता है कि यह अनचाहे अतिरिक्त काम कर रहा है। – dats

+0

@dats यह एक दिलचस्प बात है - मेरा विचार यह है कि कॉलर टी की अपेक्षा करेगा वह कॉल के बाद शून्य होने के लिए रावल्यू स्रोत की क्षमता है, जो अन्यथा मामला नहीं होगा। – Daniel

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