2010-01-05 6 views
9

निम्नलिखित उदाहरण में मुझे बिट्स के स्वैप की उम्मीद थी। इसके बजाय दूसरी बिट अधिलेखित हो जाती है, लेकिन मैं अपेक्षित व्यवहार क्यों और कैसे प्राप्त कर सकता हूं?क्यों std :: bitset उदाहरण में बिट्स का स्वैप काम नहीं करता है?

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

using namespace std; 

int main() 
{ 
    bitset<2> test(string("10")); 
    cout << test; // Prints "10" 
    swap(test[0], test[1]); 
    cout << test; // Prints "11", why not "01"? 
} 

उत्तर

13

यह शुद्ध बुरा है। पहले हम स्वैप की घोषणा को देखने के लिए है:

bool operator[](size_type _Pos) const; 
reference operator[](size_type _Pos); 

यहाँ referencebitset::reference, प्रभावी रूप से एक प्रॉक्सी के रूप में कार्य करता है कि bitset में एक नेस्टेड वर्ग है:

template<class T> 
void swap(T &left, T &right); 

अब, operator[]()bitset पर दो भार के है अंतर्निहित बिट्स में से एक के संदर्भ में। यह bitset और bitset में एक स्थिति है जो encapsulates है। swap की घोषणा के कारण, दूसरा अधिभार चुना गया है और हम दो bitset::reference एस स्वैप कर रहे हैं। अब यहां यह बुरा हो जाता है। के अदला-बदली का एक विशिष्ट कार्यान्वयन पर नजर डालते हैं:

template class<T> swap(T &left, T &right) { 
    T temp = left; 
    left = right; 
    right = temp; 
} 

समस्या यह है कि left और right एक bitset::reference को दोनों संदर्भों को हो रहा है। उनके पास एक ही अंतर्निहित डेटा है (क्योंकि वे प्रॉक्सी हैं; वही अर्थ bitset दोनों बिंदुओं के समान है!) वे bitset में अलग-अलग स्थितियों को समाहित करते हैं।इस प्रकार, इस left की तरह इस बारे में सोचेंऔर right कुछ bitset में स्थिति 1 है और bitset के समान bitset है! आइए हमेशा bitset को BS (जानबूझकर चुने गए) के रूप में देखें।

तो,

T temp = left; 

कहते tempBS में स्थिति 0 है।

left = right; 

सेट स्थिति 0 में BS में स्थिति 1 के लिए छोड़ दिया (जो एक साथ स्थिति 0 बदलता है temp में!)

right = temp; 

सेट स्थिति 1 सही में (BS में 0 जो सिर्फ करने के लिए स्थापित किया गया था स्थिति BS में स्थिति 1!)। तो इस गड़बड़ी के अंत में यह स्थिति 0 है जो भी स्थिति 1 थी और स्थिति 1 अपरिवर्तित है! अब, क्योंकि स्थिति 0 एलएसबी है और स्थिति 1 एमएसबी है हमारे पास है कि "10" "11" बन जाता है। बदसूरत।

आप एक template specialization के साथ इस आसपास पहुंच सकते हैं:

namespace std { 
    template<> 
    void swap<bitset<2>::reference>(
     bitset<2>::reference &left, 
     bitset<2>::reference &right 
    ) { 
     bool temp = (bool)left; 
     left = (bool)right; 
     right = (bool)temp; 
    } 
} 

तब:

int main() { 
    bitset<2> test(string("10")); 
    cout << test; // Prints "10" 
    swap(test[0], test[1]); 
    cout << test; // Prints "01", hallelujah! 
} 
+1

अच्छा काम! अविश्वसनीय रूप से सी ++ 0x भी बिट्ससेट के संबंध में 'स्वैप' का उल्लेख नहीं करता है। – Potatoswatter

+1

क्या यह वास्तव में संकलित करता है? 'परीक्षण [0]' एक अस्थायी है कि आप इसका संदर्भ नहीं ले सकते ... – Barry

2

वास्तव में, test[i] रिटर्न एक bitset संदर्भ rvalue के बाद से, मैं वास्तव में समझ में नहीं आता कि कैसे swap यहाँ संकलन कर सकते हैं। मेरे संकलक (छ ++ 4.3.3) मुझसे कहता है:

test.cpp:12: error: no matching function for call to 
    'swap(std::bitset<2u>::reference, std::bitset<2u>::reference)' 
/usr/include/c++/4.3/bits/stl_move.h:80: note: candidates are: 
    void std::swap(_Tp&, _Tp&) [with _Tp = std::bitset<2u>::reference] 
+2

हाँ। एमएसवीसी कोड स्वीकार करता है, स्वैप() में कुछ भी अच्छा नहीं होता है। –

+1

@ हंसपैसेंट वीएस इस कोड को [बग] (https://connect.microsoft.com/VisualStudio/feedback/details/775818/vc11-non-const-lvalue-reference-incorrectly-binds-to-rvalue) के कारण स्वीकार करता है जो गैर-कॉन्स लैवल्यू संदर्भों को रावल से बांधने की अनुमति देता है। मैंने बग को ऊपर उठाया (माइक्रोसॉफ्ट को इसे ठीक करने में मदद करने में मदद की) और इस बग के एक ग़लत परिणाम के उदाहरण के रूप में इस पोस्ट को एक लिंक जोड़ा। मैं आपको बग को ऊपर उठाने के लिए (हर कोई) सुझाव देता हूं। –

2

C++ एक बिट का प्रतिनिधित्व करने के लिए कोई मान प्रकार होती है, इसलिए जब आप एक bitset का एक तत्व का उपयोग करने की [] ऑपरेटर का उपयोग, क्या आप प्राप्त एक है प्रॉक्सी ऑब्जेक्ट जो आपके द्वारा अनुरोधित बिट के लिए उपनाम के रूप में कार्य करता है। उस प्रॉक्सी ऑब्जेक्ट को असाइन करना मूल बिटसेट ऑब्जेक्ट में संबंधित बिट मान को बदलता है।

Victor's answer दिखाता है, आपका कोड जीसीसी के साथ संकलित नहीं है। लेकिन मान लें कि swap पर कॉल संकलित होगा। आप कोड है कि कुछ इस तरह के बराबर मिल चाहते हैं:

void swap(std::bitset<2>::reference& a, std::bitset<2>::reference& b) 
{ 
    std::bitset<2>::reference tmp = a; 
    a = b; 
    b = tmp; 
} 

tmp घोषणा a साथ चर initializes, लेकिन यह है कि बिट की एक प्रति नहीं है। इसके बजाए, यह प्रॉक्सी ऑब्जेक्ट की एक प्रति बनाता है, इसलिए tmp को उसी बिटसेट में उसी बिट में संदर्भित करता है जो a संदर्भित करता है। अगली पंक्ति b से a असाइन करती है, जो a स्थान से बिट मान को प्रतिस्थापित करती है, इसे संदर्भित करता है और इसे छोटे स्थान b में संदर्भित करता है। अंत में, tmp का b असाइनमेंट है। लेकिन याद रखें कि tmp अभी भी उस बिट को संदर्भित करता है जो a को संदर्भित करता है। पढ़ना tmp, पढ़ने a रूप में ही है तो आप अंत में एक ही प्रभाव प्राप्त आप अगर swap सिर्फ इन दो पंक्तियों थे मिल चाहते हैं: a 0 और b 1 है

a = b; 
b = a; 

अपने कोड में,, उन के साथ ऐसा दो असाइनमेंट स्टेटमेंट्स, 11 वही है जो हम देखना चाहते हैं।

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