क्या सी ++, वेक्टर :: स्वैप विधि का उपयोग करके सी ++ में दो अलग-अलग वैक्टर स्वैप करना सुरक्षित है?


30

मान लीजिए कि आपके पास निम्नलिखित कोड हैं:

#include <iostream>
#include <string>
#include <vector>

int main()
{
    std::vector<std::string> First{"example", "second" , "C++" , "Hello world" };
    std::vector<std::string> Second{"Hello"};

    First.swap(Second);

    for(auto a : Second) std::cout << a << "\n";
    return 0;
}

वेक्टर की कल्पना करो std::string, अभी तक कक्षाएं नहीं हैं:

std::vector<Widget> WidgetVector;

std::vector<Widget2> Widget2Vector;

क्या std::vector::swapविधि के साथ दो वैक्टर को स्वैप करना अभी भी सुरक्षित है : WidgetVector.swap(Widget2Vector);या यह एक यूबी को जन्म देगा?

जवाबों:


20

यह सुरक्षित है क्योंकि स्वैप ऑपरेशन के दौरान कुछ भी नहीं बनाया गया है। केवल कक्षा के डेटा सदस्यstd::vector अदला-बदली होती है।

निम्नलिखित प्रदर्शनकारी कार्यक्रम पर विचार करें जो यह स्पष्ट करता है कि कक्षा की वस्तुओं की std::vectorअदला-बदली कैसे की जाती है।

#include <iostream>
#include <utility>
#include <iterator>
#include <algorithm>
#include <numeric>

class A
{
public:
    explicit A( size_t n ) : ptr( new int[n]() ), n( n )
    {
        std::iota( ptr, ptr + n, 0 );   
    }

    ~A() 
    { 
        delete []ptr; 
    }

    void swap( A & a ) noexcept
    {
        std::swap( ptr, a.ptr );
        std::swap( n, a.n );
    }

    friend std::ostream & operator <<( std::ostream &os, const A &a )
    {
        std::copy( a.ptr, a.ptr + a.n, std::ostream_iterator<int>( os, " " ) );
        return os;
    }

private:    
    int *ptr;
    size_t n;
};

int main() 
{
    A a1( 10 );
    A a2( 5 );

    std::cout << a1 << '\n';
    std::cout << a2 << '\n';

    std::cout << '\n';

    a1.swap( a2 );

    std::cout << a1 << '\n';
    std::cout << a2 << '\n';

    std::cout << '\n';

    return 0;
}

कार्यक्रम का आउटपुट है

0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 

0 1 2 3 4 
0 1 2 3 4 5 6 7 8 9 

जैसा कि आप केवल डेटा सदस्यों को देखते हैं ptrn हैं और सदस्य फ़ंक्शन स्वैप में स्वैप किए जाते हैं। न ही अतिरिक्त संसाधनों का उपयोग किया जाता है।

कक्षा में एक समान दृष्टिकोण का उपयोग किया जाता है std::vector

इस उदाहरण के लिए के रूप में

std::vector<Widget> WidgetVector;

std::vector<Widget2> Widget2Vector;

फिर विभिन्न वर्गों की वस्तुएं हैं। सदस्य फ़ंक्शन स्वैप उसी प्रकार के वैक्टर पर लागू होता है।


6
लेकिन ओ पी के किस वास्तविक मामले में, जहां वैक्टर बदली जा रहा है कर रहे हैं विभिन्न वर्गों?
एड्रियन मोल

4
@AdrianMole यदि वेक्टर के दिए गए प्रकार के लिए परिभाषित किया गया है तो सदस्य फ़ंक्शन स्वैप करता है। यह विभिन्न प्रकार के वैक्टर के लिए परिभाषित नहीं है। यह टेम्पलेट सदस्य कार्य नहीं है।
मास्को से व्लाद

"स्वैप एक ही प्रकार के वैक्टर पर लागू होता है" आपको "केवल" के बीच "केवल" जोड़ना चाहिए और "लागू" होना चाहिए।
एसएस ऐनी

बेशक, राज्यवार आवंटनकर्ता चीजों को बदल सकते हैं।
डिडुप्लिकेटर

21

हां, यह उसी प्रकार के वैक्टर को स्वैप करने के लिए पूरी तरह से सुरक्षित है।

वेक्टर के तहत वेक्टर केवल कुछ संकेत हैं जो वेक्टर उपयोग किए गए डेटा और अनुक्रम के "अंत" की ओर इशारा करते हैं। जब आप स्वैप कॉल करते हैं तो आप वैक्टर के बीच उन बिंदुओं का आदान-प्रदान करते हैं। आपको चिंता करने की आवश्यकता नहीं है कि वैक्टर इसके कारण समान आकार के हैं।

विभिन्न प्रकार के क्षेत्रों का उपयोग करके स्वैप नहीं किया जा सकता है swap। आपको अपने स्वयं के फ़ंक्शन को लागू करना होगा जो रूपांतरण और स्वैपिंग करता है।


3
आपको प्रश्न के दूसरे भाग पर अधिक बारीकी से देखने की आवश्यकता है।
मार्क रैनसम

@ मर्कांसोम यप। याद किया 2। अपडेट किया गया।
नाथनऑलिवर

13

क्या सी ++, वेक्टर :: स्वैप विधि का उपयोग करके सी ++ में दो अलग-अलग वैक्टर स्वैप करना सुरक्षित है?

हाँ। स्वैपिंग को आम तौर पर सुरक्षित माना जा सकता है। दूसरी ओर, सुरक्षा व्यक्तिपरक और सापेक्ष है और इसे विभिन्न दृष्टिकोणों से माना जा सकता है। जैसे, प्रश्न को संदर्भ के साथ बढ़ाए बिना संतोषजनक उत्तर देना संभव नहीं है, और यह चुनना कि किस प्रकार की सुरक्षा पर विचार किया जा रहा है।

क्या यह अभी भी std के साथ दो वैक्टर को स्वैप करने के लिए सुरक्षित है :: वेक्टर :: स्वैप विधि: WidgetVector.swap (Widget2Vector); या यह एक यूबी का नेतृत्व करेगा?

वहां यूबी नहीं होगा। हां, यह इस अर्थ में अभी भी सुरक्षित है कि कार्यक्रम बीमार है।


7

swapसमारोह के रूप में निम्नानुसार परिभाषित किया गया है: void swap( T& a, T& b );। यहाँ ध्यान दें कि दोनों aऔर bकर रहे हैं (और है होना करने के लिए) एक ही प्रकार के । (इस हस्ताक्षर से परिभाषित कोई भी कार्य नहीं है:void swap( T1& a, T2& b ) क्योंकि इसका कोई मतलब नहीं होगा!)

इसी प्रकार, वर्ग के swap()सदस्य फ़ंक्शन std::vectorको निम्नानुसार परिभाषित किया गया है:

template<class T1> class vector // Note: simplified from the ACTUAL STL definition
{
//...
public:
    void swap( vector& other );
//...
};

अब, चूंकि फ़ंक्शन पैरामीटर (जो कि फॉर्म का होगा) के लिए टेम्प्लेट ओवरराइड ( फ़ंक्शन टेम्प्लेट की विशिष्ट विशेषज्ञता देखें ) के साथ कोई 'समतुल्य' परिभाषा नहीं है template <typename T2> void swap(std::vector<T2>& other), यह पैरामीटर उसी प्रकार (टेम्पलेट) का वेक्टर होना चाहिए 'कॉलिंग' क्लास (यानी, यह भी एक होना चाहिएvector<T1> )।

आपके std::vector<Widget>और std::vector<Widget2>दो अलग-अलग प्रकार हैं, इसलिए कॉल को swapसंकलित नहीं किया जा सकता है, चाहे आप या तो ऑब्जेक्ट के सदस्य फ़ंक्शन का उपयोग करने का प्रयास करें (जैसा कि आपका कोड करता है), या विशेषज्ञता का उपयोग करके ।std::swap() फ़ंक्शन दो std:vectorऑब्जेक्ट्स को पैरामीटर के रूप में लेता है ।


8
std::vector::swapएक सदस्य समारोह है, यह एक मुक्त खड़े टेम्पलेट समारोह की विशेषज्ञता कैसे हो सकती है ???
एकॉनगुआ

1
सही परिणाम, गलत तर्क।
नाथनऑलिवर

2
@AdrianMole जबकि वहाँ के लिए एक विशेषज्ञता मौजूद है std::swap, वह यह नहीं है कि ओपी क्या उपयोग कर रहा है। जब आप करते हैं First.swap(Second);, तो आप कॉल करते हैं , std::vector::swapजो अलग-अलग कार्य हैstd::swap
NathanOliver

1
क्षमा करें, मेरा बुरा ... आप लिंक सीधे std के प्रलेखन के लिए चला जाता है :: वैक्टर के लिए स्वैप विशेषज्ञता। लेकिन यह सदस्य फ़ंक्शन से अलग है , जो मौजूद है और प्रश्न (केवल) में उपयोग किया जाता है।
एकॉनगुआ

2
रीज़निंग वास्तव में अनुरूप है: सदस्य को void swap(std::vector& other)(यानी std::vector<T>) के रूप में परिभाषित किया जाता है , न कि template <typename U> void swap(std::vector<U>& other)(सदिश के लिए टी टाइप पैरामीटर होने के नाते)।
एकांकागुआ

4

आप दो अलग-अलग प्रकार के वैक्टर को स्वैप नहीं कर सकते हैं लेकिन यह यूबी के बजाय संकलन त्रुटि है। vector::swapकेवल एक ही प्रकार और आवंटन के वैक्टर स्वीकार करता है।

यकीन नहीं है कि यह काम करेगा, लेकिन अगर आप चाहते हैं कि एक वेक्टर Widget2एस से परिवर्तित हो Widgetतो आप यह कोशिश कर सकते हैं:

std::vector<Widget2> Widget2Vector(
    std::make_move_iterator(WidgetVector.begin()),
    std::make_move_iterator(WidgetVector.end())
);

Widget2से रचनात्मक रूप से आगे बढ़ना होगा Widget


0

using std::swap; swap(a, b); तथा a.swap(b); ठीक वही शब्दार्थ है जहां बाद काम करता है; कम से कम किसी भी प्रकार के लिए। सभी मानक प्रकार उस संबंध में समझदार हैं।

जब तक आप एक दिलचस्प एलोकेटर का उपयोग नहीं करते हैं (मतलब स्टेटफुल, हमेशा बराबर नहीं, और कंटेनर स्वैप पर प्रचारित नहीं, देखें std::allocator_traits), दो स्वैपिंगstd::vector एक ही टेम्पलेट-तर्कों के साथ एस स्वैप करना केवल तीन मूल्यों (क्षमता, आकार और डेटा के लिए) का एक उबाऊ स्वैप है सूचक)। और बुनियादी प्रकार की अदला-बदली, अनुपस्थित डेटा-दौड़, सुरक्षित है और फेंक नहीं सकता।

यह भी मानक द्वारा गारंटी है। देखstd::vector::swap()

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.