C/C++ 入门(7)vector类(STL)

个人主页:仍有未知等待探索-CSDN博客

专题分栏:C++

                                                        请多多指教!

目录

一、标准库中的vector

1、了解

2、vector常用接口

二、vector的实现 

1、框架 

2、构造、析构函数

3、操作函数

三 、问题

1、由于赋值而引起的浅拷贝

2、因为类没有实例化且用了类里面声明的类型等而产生的报错

3、内部编译器错误 


一、标准库中的vector

1、了解

vector就是一个支持变长的数组。

2、vector常用接口

vector的使用不做过多强调,注重的是实现vector类。

可以点击下面的链接进入cplusplus网站,查看文档。

vector - C++ Reference

二、vector的实现 

1、框架 

#include <iostream>
#include <string>
#include <cstring>
#include <assert.h>
using namespace std;

template<class T>
class vector
{
public:
    typedef T* iterator;//普通迭代器
    typedef const T* const_iterator;//const迭代器
    // Iterators:	
    iterator begin()
    {
	    return _start;
    }
    iterator end()
    {
	    return _finish;
    }
    const_iterator begin() const
    {
	    return _start;
    }
    const_iterator end() const
    {
	    return _finish;
    }
	// 成员函数
private:
	iterator _start = nullptr;
	iterator _finish = nullptr;
	iterator _endofstorage = nullptr;
};

2、构造、析构函数

// 无参的构造必须写,因为下面实现了构造函数,编译器不会自动生成一个无参构造函数
vector(){}
// 开辟n个大小的空间,并初始化为m
vector(const int& n, const int& m = 0)
{
    // 新写法(复用reserve)
	reserve(n);
	for (int i = 0; i < n; i ++ ) _start[i] = m;
	_finish = _start + n;
}
// 用迭代器进行构造
template<class input_iterator>
vector(input_iterator start, input_iterator end)
{
	input_iterator it = start;
	while (it != end)
	{
		push_back(*it);
		it ++ ;
	}
}
// 开辟n个大小的空间,并初始化为val
// const T& val = T() -> 用一个匿名对象进行初始化,目的是为了预防vector<T>中T是一个自定义类型。
vector(size_t n, const T& val = T())
{
	resize(n, val);// 复用resize
}
// 用一个vector<T>进行拷贝构造
vector(const vector<T>& v)
{
	reserve(v.capacity());
	for (auto& e : v)
	{
        // 复用push_back()
		push_back(e);
	}
}
// 用列表进行初始化
// vector<int> v = {1, 2, 3};
// 用库函数实现的initializer_list<T>
vector(initializer_list<T> il)
{
	reserve(il.size());
	for (auto& e : il)
	{
		push_back(e);
	}
}
// 析构函数
~vector()
{
	delete[] _start;
	_start = _finish = _endofstorage = nullptr;
}

3、操作函数

vector<T>& operator=(vector<T> v)
{
	swap(v);
	return *this;
}
// Capacity:
size_t capacity() const
{
	return _endofstorage - _start;
}
size_t size() const 
{
	return _finish - _start;
}
bool empty() const
{
	return size() == 0;
}
void reserve(size_t n)
{
	if (capacity() < n)
	{
		T* tmp = new T[n];
		int old_size = size();
		//memcpy(tmp, _start, size() * sizeof(T));
		// 当T是string类型的时候,memcpy会导致浅拷贝问题,并且会同时对一块空间析构多次
		for (int i = 0; i < old_size; i ++ )
		{
			tmp[i] = _start[i];
		}
		delete[] _start;

		_start = tmp;
		_finish = tmp + old_size;
		_endofstorage = tmp + n;
	}
}
void resize(size_t n, const T& val = T())
{
	reserve(n);
	iterator it = _start;
	while (it != _endofstorage)
	{
		*it = val;
		it ++ ;
	}
}
// Element access:
T& operator[](int pos)
{
	assert(pos < size());
	return _start[pos];
}

// Modifiers:
// 在pos之前插入一个数x
void insert(iterator pos, const T& x)
{
	assert(pos >= _start);
	assert(pos <= _finish);
	if (_finish == _endofstorage)
	{
		int len = pos - _start;
		reserve(capacity() == 0 ? 4 : 2 * capacity());
		pos = _start + len;
	}
	iterator it = _finish - 1;
	while (it >= pos) 
	{
		*(it + 1) = *it;
		it -- ;
	}
	*pos = x;
	_finish ++ ;
}
// 尾插
void push_back(const T& x)
{
    // 老写法
	/*if (_finish == _endofstorage)
	{
	reserve(capacity() == 0 ? 4 : 2 * capacity());
	}
	*_finish = x;
	_finish ++ ;*/
    // 新写法
	insert(end() , x);
}
// 尾删
void pop_back()
{
	assert(!empty());
	_finish -- ;
}
// 交换函数,用库里面的swap实现指针的交换,来完成vector的交换
void swap(vector<T>& v)
{
	std::swap(_start, v._start);
	std::swap(_finish, v._finish);
	std::swap(_endofstorage, v._endofstorage);
}

三 、问题

1、由于赋值而引起的浅拷贝

如果要将一个引用进行赋值,并且没有对赋值运算符重载的话,会只进行值拷贝而导致浅拷贝。最后会使编译器对同一块空间析构多次

为什么*pos,x都是T类型的,而赋值重载却写一个vector<T>类型的就能行?

因为单参数的构造函数支持隐式类型转化,编译器会先进行构造函数,将这两个值构造成对象,然后在进行赋值。

vector<T>& operator=(vector<T> v)
{
	swap(v);
	return *this;
}

2、因为类没有实例化且用了类里面声明的类型等而产生的报错

需要在使用这个类型前面加上typename标志这是一个类型。

template<class T>
void print_vector(vector<T>& v)
{
	// 不加typename会报错,因为在这个函数模板里,vector<T>这个类并没有实例化,会不清楚const_iterator是类型还是变量
	// 加typename的含义就是告诉编译器,这个是类型
	typename vector<T>::const_iterator it = v.begin();
	//auto it = v.begin();
	while (it != v.end())
	{
		cout << *it << " ";
		it ++ ;
	}
}

 

3、内部编译器错误 

这个错误的原因是类模板或函数模板里面有语法错误。(比如说少加了一个分号等等)

相关推荐

  1. C++ 入门14:STL 容器之向量(vector

    2024-04-26 10:46:02       28 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-26 10:46:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-26 10:46:02       100 阅读
  3. 在Django里面运行非项目文件

    2024-04-26 10:46:02       82 阅读
  4. Python语言-面向对象

    2024-04-26 10:46:02       91 阅读

热门阅读

  1. Vue中嵌套路由(子路由)的使用

    2024-04-26 10:46:02       35 阅读
  2. 前端如何优化工程

    2024-04-26 10:46:02       35 阅读
  3. 基于python的NBA球员数据可视化分析的设计与实现

    2024-04-26 10:46:02       33 阅读
  4. 理解彩虹攻击:颜色缤纷的威胁

    2024-04-26 10:46:02       32 阅读
  5. hanoi塔

    hanoi塔

    2024-04-26 10:46:02      41 阅读
  6. 市场投放用户获取方面如何做数据分析

    2024-04-26 10:46:02       34 阅读
  7. Cache缓存

    2024-04-26 10:46:02       32 阅读
  8. C语言——const

    2024-04-26 10:46:02       29 阅读
  9. Python类方法装饰器

    2024-04-26 10:46:02       34 阅读
  10. 若依-禁用本地定时任务

    2024-04-26 10:46:02       40 阅读