![](/img/trans.png)
[英]Why std::swap does not work with std::bitset<n> content?
[英]Why the std::swap of Bits in a std::bitset instance doesn't work?
在下面的示例中,我希望交換位。 相反,第二位被覆蓋,但為什么以及如何實現預期的行為?
#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"?
}
這是非常討厭的。 首先我們要看看掉貨聲明:
template<class T>
void swap(T &left, T &right);
現在, bitset
上的operator[]()
有兩個重載:
bool operator[](size_type _Pos) const;
reference operator[](size_type _Pos);
這里reference
是bitset::reference
,在嵌套類bitset
,有效地充當代理引用到底層的比特之一。 它所封裝是bitset
,並在一個位置bitset
。 由於swap
的聲明,選擇了第二個重載,我們交換了兩個bitset::reference
。 現在這里變得討厭。 我們來看看swap的典型實現:
template class<T> swap(T &left, T &right) {
T temp = left;
left = right;
right = temp;
}
問題是left
和right
都是對bitset::reference
。 它們具有相同的底層數據(因為它們是代理;同樣意味着它們都指向相同的bitset
!)它們只是封裝了該bitset
不同位置。 因此,認為像這樣left
是在某些位置0 bitset
和right
是在某些位置1 bitset
和bitset
相同bitset
的left
! 讓我們永遠將這個bitset
稱為BS
(故意選擇)。
所以,
T temp = left;
說temp
是BS
位置0。
left = right;
將位置0設置在BS
中的左側位置1(同時在temp
更改位置0!)
right = temp;
設置在右側位置0位置1 BS
(這是剛剛成立到位置1 BS
!)。 因此,在這個混亂結束時,位置0是1位置,位置1不變! 現在,因為位置0是LSB而位置1是MSB,所以“10”變為“11”。 丑陋。
你可以通過模板專業化解決這個問題:
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!
}
實際上,由於test[i]
返回一個bitset引用rvalue,我真的不明白swap
如何在這里編譯。 我的編譯器(g ++ 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]
C ++中沒有值類型來表示單個位,因此當您使用[]
運算符訪問位集的元素時,您得到的是一個代理對象 ,它充當您請求的位的別名。 分配給該代理對象會更改原始bitset對象中的相應位值。
正如Victor的回答所示,您的代碼無法使用GCC進行編譯。 但是我們假設對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
初始化變量,但不會復制該位。 相反,它會生成代理對象的副本,因此tmp
指的是與a
引用的相同位集中的相同位。 下一行將b
分配給a
,其從位置a
復制位值並將其存儲在b
所指的位位置中。 最后,將tmp
分配給b
。 但請記住, tmp
仍然指的是a
所指的位。 讀取tmp
與讀取a
相同,所以如果swap
只是這兩行,你最終會獲得相同的效果:
a = b;
b = a;
在你的代碼中, a
是0, b
是1,所以使用這兩個賦值語句,11正是我們期望看到的。
#include <bitset>
#include <assert.h>
#include <stdio.h>
using namespace std;
int main()
{
bitset<128> bs(42);
bs[11]=0;
bs[12]=1;
assert(bs[12]==1);
printf("bs[11]=%d\n", (int)bs[11]);
printf("bs[12]=%d\n", (int)bs[12]);
int bsi = bs[11], bsj=bs[12];
swap(bsi, bsj);
bs[11]=bsi;
bs[12]=bsj;
printf("bs[11]=%d\n", (int)bs[11]);
printf("bs[12]=%d\n", (int)bs[12]);
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.