天天看點

關于std::vector<bool>類型使用下标運算符取值出錯的研究

問題提出

std::vectorv(1,true);

void* p = &v[0];// 此時p指向的記憶體轉成bool類型是false

但是

std::vector v2(2,1);

void* p3 = &v2[0];// 此時p指向的記憶體轉成int類型時,值正常

分析

1.一般類型的vector使用下标運算符時

_NODISCARD _Ty& operator[](const size_type _Pos) {
		auto& _My_data = _Mypair._Myval2;
。。。
		return _My_data._Myfirst[_Pos];
	}
           

2.繼續分析_My_data._Myfirst[_Pos];

1.因為auto& _My_data = _Mypair._Myval2;是以隻要分析_Mypair._Myval2._Myfirst[_Pos];即可

2._Mypair定義為_Compressed_pair<_Alty, _Scary_val> _Mypair;

3._Scary_val類型就是_Vector_val<bool _Test, class _Ty1, class _Ty2>

4.這個_Vector_val的特化類型就是_Myval2,同時_Vector_val裡面定義了_Myfirst,這就是前面下标運算符用到的指針,那麼這個指針是什麼類型呢,繼續往下看

5.看聲明,pointer _Myfirst; // pointer to beginning of array

6.再看聲明,using pointer = typename _Val_types::pointer;是以先找到_Val_types類型,再找到這個pointer類型即可

7._Val_types為_Vector_val的特化,是以我們回到_Vector_val的特化,再看特化的類型,它是conditional_t的特化版本。

_Vector_val的特化如下

using _Scary_val = _Vector_val<conditional_t<_Is_simple_alloc_v<_Alty>, _Simple_types<_Ty>,
			_Vec_iter_types<_Ty, typename _Alty_traits::size_type, typename _Alty_traits::difference_type,
    			typename _Alty_traits::pointer, typename _Alty_traits::const_pointer, _Ty&, const _Ty&>>>;
           

8.找到conditional_t的定義,using conditional_t = typename conditional<_Test, _Ty1, _Ty2>::type;

9.再找到conditional的定義

template <bool _Test, class _Ty1, class _Ty2>

struct conditional { // Choose _Ty1 if _Test is true, and _Ty2 otherwise

using type = _Ty1;

};

10.是以conditional_t的類型即為conditional特化時,第二個模闆參數類型,也就是conditional_t特化時的第二個模闆參數類型,回到_Vector_val的特化,可以看到這個類型是_Simple_types<_Ty>

11.進到Simple_types<_Ty>的定義

using pointer = value_type*; 等價于using pointer = _Ty*

12.這個_Ty類型就是我們構造vector對象時傳入的模闆參數類型,是以pointer就是對應的指針,也就相當于數組指針(這一點可以到vector構造時調用的 _Construct_n_copies_of_ty()裡面得到證明)

13.是以最後得出結論:一般類型的vector下标運算結果是這種類型的值引用

3.下面分析bool類型的vector使用下标運算傳回的類型

1.進到定義

_NODISCARD reference operator[](size_type _Off) {
		iterator _It = begin();
		_It._Advance(_Off);
		return *_It;
	}
           

2.reference定義如下

template <class _Alvbase_wrapped>
		   class _Vb_reference : public _Vb_iter_base<_Alvbase_wrapped> { // reference to a bit within a base word
		   。。。。
		   }
           

3.從定義可以看出reference是一個類類型,這個類是疊代器的叔叔類,是以在1中實際上發生了隐式類型轉換

4.那麼這個reference的值是怎麼計算的呢,這一點沒有去深究

4.結論

bool類型存入vector,再用下标運算符取出來的是reference類的拷貝,再使用取址符得到的是這個類的位址,沒有參考意義。而普通類型用下标運算符算出來的就是這個類型的值引用,是以與期望一緻

繼續閱讀