vector增容存在的问题,下面笔者给出目前遇到的两个,后续遇到则继续补充
1 浅拷贝问题
- 当开辟新空间时候,若就空间内存在指针,比如存放string,采用 memcpy() 则会导致浅拷贝问题
【解决】通过赋值操作,调用string的 operator= 操作
void reserve(size_t n) {
if (n > capacity()) {
size_t num = size();
// 开辟空间,转移数据
T* tmp = new T[n];
// 浅拷贝问题
//if (_start) memcpy(tmp, _start, sizeof(T) * num);
if (_start) {
for (size_t i = 0; i < num; ++i) {
tmp[i] = _start[i]; // 本质调用string类的operator=深拷贝, 即 string s1 = s2;
}
delete[] _start;
}
_start = tmp;
_finish = tmp + num;
_end_of_storage = tmp + n;
}
}
2 迭代器失效
1.开辟新空间后,自身的迭代器失效
// 重新设置自身迭代器
iterator = vector.begin();
2 开辟新空间后,函数传参的迭代器失效
// 重新设置
iterator insert(iterator pos, const T& x) {
assert(pos <= _finish);
if (_finish == _end_of_storage) {
size_t num = size();
size_t newcap = (capacity() == 0) ? 2 : capacity() * 2;
reserve(newcap);
// 更新pos位置
pos = _start + num;
}
// 移动数据 (有数据的时候)
if (_start != _finish) {
iterator cur = _finish - 1;
while (cur >= pos) {
*(cur + 1) = *cur;
--cur;
}
}
// 插入 (无数据则直接插入)
*pos = x;
++_finish;
return pos;
}
3 最后给出vector基本的成员函数
#pragma once
#include <iostream>
#include <assert.h>
using namespace std;
namespace yu
{
template <class T>
class myvector {
public:
// ****************************** 迭代器
typedef T* iterator;
typedef const T* const_iterator;
iterator begin() const{
return _start;
}
const_iterator cbegin() const {
return _start;
}
iterator end() const{
return _finish;
}
const_iterator cend() const {
return _finish;
}
// ******************************
// ****************************** 构造函数
// 1 默认构造
myvector() : _start(nullptr), _finish(nullptr), _end_of_storage(nullptr)
{
}
// 2 有参构造
vector(size_t n, const T& value = T())
: _start(nullptr)
, _finish(nullptr)
, _endOfStorage(nullptr)
{
reserve(n);
while (n--)
{
push_back(value);
}
}
/*
* 理论上将,提供了vector(size_t n, const T& value = T())之后
* vector(int n, const T& value = T())就不需要提供了,但是对于:
* vector<int> v(10, 5);
* 编译器在编译时,认为T已经被实例化为int,而10和5编译器会默认其为int类型
* 就不会走vector(size_t n, const T& value = T())这个构造方法,
* 最终选择的是:vector(InputIterator first, InputIterator last)
* 因为编译器觉得区间构造两个参数类型一致,因此编译器就会将InputIterator实例化为int
* 但是10和5根本不是一个区间,编译时就报错了
* 故需要增加该构造方法
*/
vector(int n, const T& value = T())
: _start(new T[n])
, _finish(_start + n)
, _endOfStorage(_finish)
{
for (int i = 0; i < n; ++i)
{
_start[i] = value;
}
}
// 若使用iterator做迭代器,会导致初始化的迭代器区间[first,last)只能是vector的迭代器
// 重新声明迭代器,迭代器区间[first,last)可以是任意容器的迭代器
template<class InputIterator>
vector(InputIterator first, InputIterator last)
{
while (first != last)
{
push_back(*first);
++first;
}
}
// 3 拷贝构造 法1
#if 0
myvector(const myvector<T>& v): _start(nullptr), _finish(nullptr), _end_of_storage(nullptr)
{
_start = new T[v.capacity()];
_finish = _start;
_end_of_storage = _start + v.capacity();
for (size_t i = 0; i < v.size(); ++i) {
*_finish = v[i];
++_finish;
}
}
#endif
#if 1
// 法2
myvector(const myvector<T>& v) : _start(nullptr), _finish(nullptr), _end_of_storage(nullptr)
{
reserve(v.capacity());
// 范围for调用的是const成员函数 begin()
for (const auto& e : v) {
push_back(e);
}
}
#endif
// 4 赋值运算符重载 法1
// v1 = v2
#if 0
myvector<T>& operator=(const myvector<T>& v) {
myvector<T> tmp(v);
_start = nullptr;
_finish = nullptr;
_end_of_storage= nullptr;
swap(_start, tmp._start);
swap(_finish, tmp._finish);
swap(_end_of_storage, tmp._end_of_storage);
return *this;
}
#elif 1
// 法2 通过传值拷贝 现代写法
void swap( myvector<T> v) {
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_end_of_storage, v._end_of_storage);
}
myvector<T>& operator=( myvector<T> v) {
swap(v);
return *this;
}
#endif
// 5 析构函数
~myvector() {
delete[] _start;
_start = _finish = _endOfStorage = nullptr;
}
}