allocator类型
new实现了分配内存和初始化的整合,但是在分配大块内存时,对所有位置都调用构造函数是低效的,应该在使用时才初始化该位置。所以必须单独进行内存分配和初始化。依赖于allocator的
T* allocate(size_t); //分配内存
construct(T*, args);//构造函数
destroy(T*);//析构
deallocate(T*, size_t);//释放内存
vector容器
容器分为两部分,first~ finish是分配空间且初始化元素的,finish~ end_of_storage是只分配空间。有两种操作:对元素操作,构造/析构对象,影响size();对空间操作,影响capcity()。
vector的size随元素增减而变化,但capcity只增加不减少。除非移动语义下替换容器空间。remove时,是把值不等于val的元素移到前面,不改变容器size。erase时,析构指定位置的元素,影响size,不影响capcity。
要区分元素是指针还是对象。如果元素是对象,释放元素空间时先析构再释放;如果元素是指针,那么数组存储指针,然后指针指向一块内存,释放元素空间时只是释放容器的空间,指针指向的内存却无法释放。
namespace ch {
template<typename T>
class Vector
{
public:
typedef T* iterator;
friend iterator remove(iterator first, iterator last, T val);
private:
iterator start;
iterator finish;
iterator end_of_storage;
static allocator<T> alloc;
public:
Vector() :start(nullptr), finish(nullptr), end_of_storage(nullptr) {}
Vector(const Vector& v)//拷贝构造
{
size_t n = v.finish - v.start;
iterator ptr = v.start;
finish = start = alloc.allocate(n);
while (ptr != v.finish)
{
alloc.construct(finish++, *ptr++);
}
end_of_storage = finish;
}
Vector(const Vector&& v)//移动构造
{
start = v.start;
finish = v.finish;
end_of_storage = v.end_of_storage;
v.start = v.finish = v.end_of_storage = nullptr;
}
~Vector()
{//析构start~finish元素,释放start~end_of_storage空间
iterator ptr = start;
while (ptr != finish)
alloc.destroy(ptr++);
alloc.deallocate(start, end_of_storage - start);
}
Vector& operator=(const Vector& v)
{
if (v == *this) return *this;
//析构元素
iterator ptr = start;
while (ptr != finish)
alloc.destroy(ptr++);
//如果新空间比原有空间大,就重新分配,否则不重新分配空间。
size_t n = v.end_of_storage - v.start;
if (n > end_of_storage - start)
{
alloc.deallocate(start, end_of_storage - start);
finish = start = alloc.allocate(n);
ptr = v.start;
while (ptr != v.finish)
{
alloc.construct(finish++, *ptr++);
}
end_of_storage = start + n;
}
else {
finish = start;
ptr = v.start;
while (ptr != v.finish)
{
alloc.construct(finish++, *ptr++);
}
}
return *this;
}
Vector& operator=(const Vector&& v)
{//移动赋值运算符,另一个容器的空间偷过来,所以capcity可能会减小。
if (v == *this) return *this;
//析构元素,并释放空间。
iterator ptr = start;
while (ptr != finish)
alloc.destroy(ptr++);
alloc.deallocate(start, end_of_storage - start);
finish = v.finish;
start = v.start;
end_of_storage = v.end_of_storage;
v.finish = v.start = v.end_of_storage = nullptr;
}
/*erase:析构某位置元素,并返回下一元素的迭代器。
*/
iterator erase(iterator first, iterator last)
{
iterator a = first, b = last;
while (b != finish)
* a++ = *b++;
while (a != finish)
alloc.destroy(a++);
finish = finish - (last - first);
return first;
}
iterator erase(iterator pos)
{
iterator a = pos, b = pos + 1;
while (b != finish)
* a++ = *b++;
finish--;
alloc.destroy(finish);
return pos;
}
void push_back(const T& t)
{
if (finish == end_of_storage)
{
size_t n = end_of_storage - start > 0 ? 2 * (end_of_storage - start) : 1;
//先分配新空间,拷贝值,再释放原空间
iterator new_start = nullptr, new_finish = nullptr;
new_finish = new_start = alloc.allocate(n);
iterator old_p = start, new_p = new_start;
while (old_p != finish)
alloc.construct(new_p++, *old_p++);
new_finish = new_p;
old_p = start;
while (old_p != finish)
alloc.destroy(old_p++);
alloc.deallocate(start, end_of_storage - start);
start = new_start;
finish = new_finish;
end_of_storage = new_start + n;
}
alloc.construct(finish, t);
finish++;
}
void push_back(const T&& t)
{
if (finish == end_of_storage)
{
size_t n = end_of_storage - start > 0 ? 2 * (end_of_storage - start) : 1;
//先分配新空间,拷贝值,再释放原空间
iterator new_start = nullptr, new_finish = nullptr;
new_finish = new_start = alloc.allocate(n);
iterator old_p = start;
iterator new_p = new_start;
while (old_p != finish)
alloc.construct(new_p++, *old_p++);
new_finish = new_p;
old_p = start;
while (old_p != finish)
alloc.destroy(old_p++);
alloc.deallocate(start, end_of_storage - start);
start = new_start;
finish = new_finish;
end_of_storage = new_start + n;
}
alloc.construct(finish, std::move(t));
finish++;
}
size_t size() const { return finish - start; }
size_t capcity() const { return end_of_storage - start; }
iterator begin() const { return start; }
iterator end() const { return finish; }
};
template<typename T>
allocator<T> Vector<T>::alloc;
/*类模板的非约束参数的友元函数。
remove:将与目标值不相等的元素拷贝到前面,返回不相等区下一个位置。
*/
template<typename T>
typename ch::Vector<T>::iterator remove(typename ch::Vector<T>::iterator first,
typename ch::Vector<T>::iterator last, T val)
{
typedef typename ch::Vector<T>::iterator iterator;
iterator fast = first, low = first;
while (fast != last)
{
if (*fast != val)
*low++ = *fast++;
else
fast++;
}
return low;
}
};
常见vector操作
ch::Vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(3);
v.push_back(5);
//删除等于3的所有元素
v.erase(ch::remove<ch::Vector<int>::iterator, int>(v.begin(), v.end(), 3), v.end());
//删除所有元素,当然容器空间没有释放。
ch::Vector<int>::iterator it = v.begin();
while (it != v.end())
it = v.erase(it);
- 移动语义
从源对象向新对象拷贝时会占用大量时间,当源对象时临时对象(右值)或不再使用时(可转变为右值),可使用移动语义。
(1)首先利用std::move将对象转换成右值
(2)把源对象的内部指针拷贝过来,并将其赋值为nullptr,避免重复释放内存。
(3)源对象成为右值对象后不就会被系统释放掉。