allocator
以及vector构造、析构函数的基本实现。vector
的move
构造函数的定义vector
的 erase clear pop_back
三个函数,以及size_t
与 ptrdiff_t
的区别vector
的 operator[]
操作符重载分析实现源码,其实我们只用实现,理解几个核心的函数就可以明白其中的原理,并不需要全部的实现。太多实现函数,会让我们分不清重点,而且看起来头大。
下面给出move
构造函数的定义(只需要交换内部指针即可):
template
SimpleVec::SimpleVec(SimpleVec&& v){
start_ = v.start_;
finish_ = v.finish_;
end_of_storage_ = v.end_of_storage_;
v.start_ = v.finish_ = v.end_of_storage_ = 0;
}
pop_back
函数最为简单,只需finish_向前移动,并析构对象即可template<typename T, typename Alloc>
void SimpleVec::pop_back(){
--finish_;
destroy(finish_);
}
template<typename T, typename Alloc>
void SimpleVec::clear(){
// 仅仅调用对象的析构函数,不释放内存
destroy(start_, finish_);
// end_of_storage_不改变,容量还是保留
finish_ = start_;
}
template<typename T, typename Alloc>
//terator SimpleVec::erase(iterator position){
typename SimpleVec::iterator SimpleVec::erase(iterator position){
erase(position, position + 1);
}
template<typename T, typename Alloc>
typename SimpleVec::iterator SimpleVec::erase(iterator first, iterator last){
// 尾部残留对象数
difference_type len_of_tail = finish_ - last;
// 删去的对象数目
difference_type len_of_erase = last - first;
// 如果len_of_erase < 0 就有问题
finish_ -= len_of_erase;
//由前往后赋值
for (size_t i = 0; i < len_of_tail; ++i) {
*(first + i) = *(last + i);
}
return first;
}
上面的erase函数要注意,必须要先destory [first, last)范围的对象,不然直接安装上面的赋值会导致对象的析构函数没有被调用。
size_t
与 ptrdiff_t
的区别ptrdiff_t
这个类型有疑问,下面说明下其与size_t
的区别。ptrdiff_t
,它是一种有符号整数类型
。减法运算的值为两个指针在内存中的距离(以数组元素的长度为单位,而非字节),因为减法运算的结果将除以数组元素类型的长度。所以该结果与数组中存储的元素的类型无关
。size_t是unsigned类型,用于指明数组长度或下标,它必须是一个正数,std::size_t.设计size_t就是为了适应多个平台,其引入增强了程序在不同平台上的可移植性。
ptrdiff_t是signed类型,用于存放同一数组中两个指针之间的差距,它可以使负数,std::ptrdiff_t.同上,使用ptrdiff_t来得到独立于平台的地址差值.
一般在STL中会定义 size_type
与 difference_type
,如下:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
下面给出,size_t
, ptrdiff_t
测试实例如下:
vector<int> ivec{1, 2, 3, 4, 5, 6};
vector<double> dvec{1, 2, 3, 4, 5, 6};
// 无论double还是int长度都是6
ptrdiff_t i_p1 = ivec.end() - ivec.begin(); // 6
ptrdiff_t i_p2 = ivec.begin() - ivec.end(); // -6
cout<<"ptrdiff_t - i_p1: "<" i_p2: "<// ptrdiff_t - i_p1: 6 i_p2: -6
size_t s_p1 = ivec.end() - ivec.begin(); // 6
size_t s_p2 = ivec.begin() - ivec.end(); // 18446744073709551610
cout<<"size_t - : s_p1: "<" s_p2: "<// size_t - : s_p1: 6 s_p2: 18446744073709551610
ptrdiff_t d_p1 = dvec.end() - dvec.begin(); // 6
ptrdiff_t d_p2 = dvec.begin() - dvec.end(); // -6
cout<<"ptrdiff_t - : d_p1: "<" d_p2: "<// ptrdiff_t - : d_p1: 6 d_p2: -6
size_t d_s1 = dvec.end() - dvec.begin(); // 6
size_t d_s2 = dvec.begin() - dvec.end(); // 18446744073709551610
cout<<"size_t - : d_s1: "<" d_s2: "<// size_t - : d_s1: 6 d_s2: 18446744073709551610
无论是double(字节大小为8)
还是int(字节大小为4)
容器迭代器的长度差值与字节无关,如下我们可以看到-6 转为 size_t:
size_t s_minus = -6;
cout<<"-6 to size_t is: "<6 to size_t is: 18446744073709551610
接下来分析operator[], vector中返回的对象有引用版本和非要用版本,如果不返回引用那么=的时候会创建一个临时对象构造新的对象,在一定程度上导致程序性能下降。
stl::vector中声明如下:
reference operator[] (size_type n);
const_reference operator[] (size_type n) const;
定义如下:
reference operator[](const size_t i){
return *(begin() + i);//begin()
const_reference operator[](const size_t i)const{
return *(begin() + i); //begin()const
}
注意:上面的operator[]下面的那个实用的是begin()const
iterator begin(){return start_;}
iterator begin()const{return start_;}
stack overflow中有个关于operators []的问题:Why std::vector has 2 operators [] realization ?
reference operator[]( size_type pos );
const_reference operator[]( size_type pos ) const;
原因如下:
void f(std::vector<int> & v1, std::vector<int> const & v2)
{
//v1 is non-const vector
//v2 is const vector
auto & x1 = v1[0]; //invokes the non-const version
auto & x2 = v2[0]; //invokes the const version
v1[0] = 10; //okay : non-const version can modify the object
v2[0] = 10; //compilation error : const version cannot modify
x1 = 10; //okay : x1 is inferred to be `int&`
x2 = 10; //error: x2 is inferred to be `int const&`
}
非const版本
好理解,我们定义一个引用到vector
对象就可以改变vector
中的成员了。const版本
,我们定义一个引用到vector
对象不改变vector
中的成员了。下面在给出 operator==
operator!=
的实现:
template<typename T, typename Alloc>
bool SimpleVec::operator==(const SimpleVec& v)const{
if(size() != v.size()){
return false;
} else{
auto p1 = start_;
auto p2 = v.start_;
for(;p1 < finish_ && p2 < v.finish_;++p1, ++p2){
if(*p1 != *p2)return false;
}
return true;
}
};
template<typename T, typename Alloc>
bool SimpleVec::operator!=(const SimpleVec& v)const{
return !(*this == v);
}
https://blog.csdn.net/honpey/article/details/8796386(size_t
与 ptrdiff_t
的区别部分参考)
https://stackoverflow.com/questions/14860622/c-stdvector-operator