📌 相关专栏
-
【C++ 专栏】
📌 相关文章推荐
很高兴你点开这篇文章✨
这里会持续更新更多有用的内容,关注我,一起慢慢变好呀
👍 点赞 ⭐ 收藏 💬 评论
文章目录
- 前言
- [1. 核心架构:三指针内存管理](#1. 核心架构:三指针内存管理)
- [2. 迭代器设计](#2. 迭代器设计)
- [3. 构造与析构](#3. 构造与析构)
-
- [3.1 无参构造](#3.1 无参构造)
- [3.2 析构函数](#3.2 析构函数)
- [3.3 clear:清空数据](#3.3 clear:清空数据)
- [4. 容量管理:size、capacity、reserve、resize](#4. 容量管理:size、capacity、reserve、resize)
-
- [4.1 reserve:预分配空间(核心实现)](#4.1 reserve:预分配空间(核心实现))
- [4.2 resize:调整有效元素个数](#4.2 resize:调整有效元素个数)
- [4.3 operator :下标访问](#4.3 operator[ ]:下标访问)
- [5. 增删操作:push_back、pop_back](#5. 增删操作:push_back、pop_back)
-
- [5.1 push_back:尾插](#5.1 push_back:尾插)
- [5.2 pop_back:尾删](#5.2 pop_back:尾删)
- [6. 插入与删除:insert、erase(含迭代器失效)](#6. 插入与删除:insert、erase(含迭代器失效))
-
- [6.1 insert:指定位置插入](#6.1 insert:指定位置插入)
- [6.2 erase:指定位置删除](#6.2 erase:指定位置删除)
- [6.3 迭代器失效问题及解决方案](#6.3 迭代器失效问题及解决方案)
- [7. 拷贝控制:拷贝构造、赋值运算符、swap](#7. 拷贝控制:拷贝构造、赋值运算符、swap)
-
- [7.1 拷贝构造](#7.1 拷贝构造)
- [7.2 swap:交换三个指针](#7.2 swap:交换三个指针)
- [7.3 赋值运算符重载(现代写法)](#7.3 赋值运算符重载(现代写法))
- [8. 扩展构造接口](#8. 扩展构造接口)
-
- [8.1 迭代器区间构造(函数模板)](#8.1 迭代器区间构造(函数模板))
- [8.2 n 个 val 构造](#8.2 n 个 val 构造)
- [8.3 全局打印函数(typename 的使用)](#8.3 全局打印函数(typename 的使用))
- [9. 完整测试用例](#9. 完整测试用例)
-
- [test 1 :增删操作与迭代器失效](#test 1 :增删操作与迭代器失效)
- [test 2 :拷贝构造与赋值](#test 2 :拷贝构造与赋值)
- [test 2 :迭代器区间构造与 n 个 val 构造](#test 2 :迭代器区间构造与 n 个 val 构造)
- 总结
- 本文全部代码
-
- [🐾 vector.h](#🐾 vector.h)
- [🐾 Test.cpp](#🐾 Test.cpp)
前言
std::vector 是 C++ 中最常用的容器之一,它封装了动态数组,能够自动扩容。但你知道它是如何通过三个指针来管理内存的吗?为什么 insert 后迭代器会失效?如何实现一个正确的拷贝构造和赋值运算符?
- 三指针架构:
_start、_finish、_end_of_storage- 迭代器本质:
对原生指针的封装- 迭代器失效:
扩容和删除导致的野指针问题- 深拷贝:
自定义类型的内存管理
🐶 🐾 ✨ 🐾 🐶
1. 核心架构:三指针内存管理
vector 本质是动态管理连续内存的容器,通过三个指针(迭代器) 控制内存块:
_start:指向内存块的起始位置(第一个元素的地址)_finish:指向有效元素的末尾(最后一个元素的下一位)_end_of_storage:指向内存块的,末尾(容量的边界)
cpp
namespace Myvector
{
template<class T>
class vector
{
private:
iterator _start = nullptr; // 指向内存块起始位置(第一个元素)
iterator _finish = nullptr; // 指向有效元素末尾(最后一个元素的下一位)
iterator _end_of_storage = nullptr; // 指向内存块末尾(容量的边界)
};
}
三个指针的演示图:
三指针的计算指标:
cpp
size_t size() const
{
return _finish - _start; // 有效元素个数
}
size_t capacity() const
{
return _end_of_storage - _start; // 总容量
}
优点 :无需额外成员变量存储 size 和 capacity,通过指针差值即可计算,简洁高效。
🐶 🐾 ✨ 🐾 🐶
2. 迭代器设计
vector 的迭代器就是对原生指针的类型别名:
cpp
typedef T* iterator; // 普通迭代器,可读写
typedef const T* const_iterator; // 常量迭代器,只读
迭代器接口实现:
cpp
iterator begin() { return _start; }
iterator end() { return _finish; }
const_iterator begin() const { return _start; }
const_iterator end() const { return _finish; }
注意 :由于 vector 内存是连续的,原生指针本身就支持 ++、--、+n、-n、* 等操作,符合迭代器要求,因此可以直接用 T* 作为迭代器。
🐶 🐾 ✨ 🐾 🐶
3. 构造与析构
3.1 无参构造
cpp
vector()
: _start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{
}
3.2 析构函数
cpp
~vector()
{
if (_start) // _start 不为空才需要释放
{
delete[] _start;
_start = _finish = _end_of_storage = nullptr;
}
}
3.3 clear:清空数据
cpp
void clear()
{
_finish = _start; // 只清空数据,不改变空间大小
}
🐶 🐾 ✨ 🐾 🐶
4. 容量管理:size、capacity、reserve、resize
4.1 reserve:预分配空间(核心实现)
reserve 是最核心的扩容函数,所以我们需要特别注意深拷贝问题:
cpp
void reserve(size_t n)
{
if (n > capacity())
{
size_t old_size = size(); // 1. 保存原大小空间
T* tmp = new T[n]; // 2. 开辟新空间
// 3. 拷贝元素(深拷贝)
// !! 不能用 memcpy!自定义类型会浅拷贝导致问题
for (size_t i = 0; i < old_size; i++)
{
tmp[i] = _start[i]; // 调用赋值运算符重载(深拷贝)
}
delete[] _start; // 4. 释放原空间
_start = tmp; // 5. 指向新空间
_finish = _start + old_size; // 6. 更新 _finish
_end_of_storage = _start + n; // 7. 更新容量边界
}
}
关键点:
不能使用 memcpy 进行浅拷贝,自定义类型(如 string)会出问题必须逐元素赋值,调用 T 的赋值运算符实现深拷贝需要提前保存 old_size,因为 delete[] 后 size() 无法使用
4.2 resize:调整有效元素个数
cpp
void resize(size_t n, T val = T()) // T() 是匿名对象,作为缺省值,如果调用时不写第二个参数,就要用T类型的默认构造对象来填充
{
if (n < size()) // 情况1:缩小
{
_finish = _start + n;
}
else // 情况2:扩大
{
if (n > capacity())
{
reserve(n); // 先扩容
}
while (_finish < _start + n) // 填充 val
{
*_finish = val;
_finish++;
}
}
}
关于 = T() 的解读:
当 T 是 int 时,T() 就是 0当 T 是 string 等自定义类型时,T() 调用其默认构造函数这是模板编程中获取类型默认值的常用技巧
4.3 operator :下标访问
cpp
T& operator[](size_t i)
{
assert(i < size());
return _start[i];
}
const T& operator[](size_t i) const
{
assert(i < size());
return _start[i];
}
🐶 🐾 ✨ 🐾 🐶
5. 增删操作:push_back、pop_back
5.1 push_back:尾插
cpp
void push_back(const T& x)
{
if (_finish == _end_of_storage) // 空间不足,需要扩容
{
reserve(capacity() == 0 ? 4 : 2 * capacity()); // 扩容策略:空时开4,否则翻倍
}
*_finish = x; // 赋值
_finish++; // 更新 _finish
}
5.2 pop_back:尾删
cpp
bool empty() const
{
return _start == _finish;
}
void pop_back()
{
assert(!empty());
--_finish; // 只需移动指针
}
注意 :pop_back 并不释放内存,只是将 _finish 前移。
🐶 🐾 ✨ 🐾 🐶
6. 插入与删除:insert、erase(含迭代器失效)
6.1 insert:指定位置插入
cpp
void insert(iterator pos, const T& x)
{
assert(pos >= _start && pos < _finish);
if (_finish == _end_of_storage) // 需要扩容
{
size_t len = pos - _start; // 保存偏移量
reserve(capacity() == 0 ? 4 : 2 * capacity());
pos = _start + len; // 🔴 关键:修正迭代器
}
iterator end = _finish - 1;
while (end >= pos) // 从后往前移动元素
{
*(end + 1) = *end;
end--;
}
*pos = x;
_finish++;
}
6.2 erase:指定位置删除
cpp
iterator erase(iterator pos)
{
assert(pos >= _start && pos < _finish);
iterator it = pos + 1;
while (it != end()) // 从前往后移动元素
{
*(it - 1) = *it;
it++;
}
_finish--;
return pos; // 返回被删除位置的下一个迭代器
}
6.3 迭代器失效问题及解决方案
什么是迭代器失效?
当 vector 扩容时,原内存被 delete,指向原内存的迭代器变成野指针删除元素后,被删除位置之后的迭代器可能失效
场景1:insert 扩容导致的失效
cpp
// 错误示例
Myvector::vector<int>::iterator p = v1.begin() + 2;
v1.insert(p, 6); // 如果 insert 触发了扩容,p 变成野指针
*p *= 10; // ❌ 非法访问!因为p已失效
// 正确做法:重新获取迭代器
p = v1.begin() + 2; // 重新计算
*p *= 10; // ✅ 安全
场景2:erase 删除导致的失效
cpp
// 错误示例
auto it = v1.begin();
while (it != v1.end())
{
if (*it % 2 == 0)
{
v1.erase(it); // ❌ erase 后 it 失效,无法再使用
}
else
{
it++;
}
}
// 正确做法:使用返回值更新迭代器
auto it = v1.begin();
while (it != v1.end())
{
if (*it % 2 == 0)
{
it = v1.erase(it); // ✅ 接收返回的新迭代器
}
else
{
it++;
}
}
核心原则:
insert 和 erase 操作后,原有的迭代器可能失效如果需要继续使用,必须重新获取或接收返回值
🐶 🐾 ✨ 🐾 🐶
7. 拷贝控制:拷贝构造、赋值运算符、swap
7.1 拷贝构造
cpp
vector(const vector<T>& v)
{
reserve(v.size()); // 提前开好空间
for (auto& e : v) // 范围 for 遍历
{
push_back(e);
}
}
7.2 swap:交换三个指针
cpp
void swap(vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_end_of_storage, v._end_of_storage);
}
7.3 赋值运算符重载(现代写法)
cpp
// 现代写法:传值 + swap
vector<T>& operator=(vector<T> v) // ⚠️ 传值,不是引用
{
if (this != &v)
{
swap(v); // 交换内容
}
return *this;
}
为什么用传值而不是传引用?
传值时,形参 v 是实参的副本(调用拷贝构造)swap 交换 *this 和 v 的内容函数结束时,v 被销毁,原 *this 的内容也随之释放好处:自动处理了深拷贝和异常安全,代码简洁
🐶 🐾 ✨ 🐾 🐶
8. 扩展构造接口
8.1 迭代器区间构造(函数模板)
cpp
// 类模板的成员函数,也可以是函数模板
template<class InputIterator>
vector(InputIterator first, InputIterator last)
{
while (first != last)
{
push_back(*first);
first++;
}
}
🐾 使用 InputIterator 而不是 iterator,可以接受任意容器的迭代器,不限于 vector 自身。
8.2 n 个 val 构造
cpp
vector(size_t n, const T& val = T())
{
reserve(n);
for (size_t i = 0; i < n; i++)
{
push_back(val);
}
}
8.3 全局打印函数(typename 的使用)
cpp
template <class T>
void print_vector(const vector<T>& v)
{
// 编译器无法区分 const_iterator 是类型还是静态成员
// vector<T>::const_iterator it = v.begin(); // ❌ 编译错误
// 解决方案1:加 typename 告诉编译器这是一个类型
typename vector<T>::const_iterator it = v.begin();
// 解决方案2:使用 auto(推荐)
// auto it = v.begin();
while (it != v.end())
{
cout << *it << " ";
it++;
}
cout << endl;
}
关于 typename :对于未实例化的类模板,编译器无法区分 const_iterator 是类型名还是静态成员变量,需要 typename 关键字显式声明。
🐶 🐾 ✨ 🐾 🐶
9. 完整测试用例
test 1 :增删操作与迭代器失效
cpp
void test_vector1()
{
Myvector::vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
print_vector(v1); // 1 2 3 4 5
v1.pop_back();
print_vector(v1); // 1 2 3 4
v1.insert(v1.begin() + 1, 5);
print_vector(v1); // 1 5 2 3 4
// 迭代器失效演示
Myvector::vector<int>::iterator p = v1.begin() + 2;
v1.insert(p, 6);
p = v1.begin() + 2; // 必须重新获取
*p *= 10;
print_vector(v1); // 1 5 60 2 3 4
v1.erase(v1.begin() + 2);
print_vector(v1); // 1 5 2 3 4
// 删除所有偶数(使用返回值避免失效)
auto it = v1.begin();
while (it != v1.end())
{
if (*it % 2 == 0)
{
it = v1.erase(it);
}
else
{
it++;
}
}
print_vector(v1); // 1 5 3
}
test 2 :拷贝构造与赋值
cpp
void test_vector2()
{
Myvector::vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
auto v2 = v1; // 拷贝构造
print_vector(v2); // 1 2 3
Myvector::vector<int> v3;
v3 = v1; // 赋值运算符
print_vector(v3); // 1 2 3
// 自定义类型测试
Myvector::vector<string> v;
v.push_back("111");
v.push_back("222");
v.push_back("333");
v.push_back("444");
v.push_back("555"); // 触发扩容
print_vector(v); // 111 222 333 444 555
}
test 2 :迭代器区间构造与 n 个 val 构造
cpp
void test_vector3()
{
Myvector::vector<int> v1;
for (int i = 1; i <= 5; i++) v1.push_back(i);
print_vector(v1); // 1 2 3 4 5
// 迭代器区间构造
Myvector::vector<int> v2(v1.begin() + 1, v1.begin() + 4);
print_vector(v2); // 2 3 4
// n 个 val 构造
Myvector::vector<int> v3(10);
print_vector(v3); // 0 0 0 0 0 0 0 0 0 0
Myvector::vector<int> v4(10u, 1); // 10u 是 size_t,避免误调迭代器构造
print_vector(v4); // 1 1 1 1 1 1 1 1 1 1
}
🐶 🐾 ✨ 🐾 🐶
总结
| 模块 | 关键实现 |
|---|---|
| 内存管理 | 三指针架构: _start、_finish、_end_of_storage |
| 迭代器 | 原生指针 T* 封装 |
| 扩容 | reserve + 深拷贝(逐元素赋值,不能用 memcpy) |
| 插入删除 | insert/erase + 迭代器失效处理 |
| 拷贝控制 | 拷贝构造、现代写法赋值运算符(传值 + swap) |
| 类型萃取 | T() 获取类型默认值、typename 解决依赖类型 |
迭代器失效总结:
insert 扩容后,所有迭代器都可能失效erase 后,被删除位置之后的迭代器失效解决方案:重新获取或接收返回值
🐶 🐾 ✨ 🐾 🐶
本文全部代码
🐾 vector.h
cpp
#pragma once
#include<iostream>
#include<assert.h>
#include<string>
using namespace std;
//三指针控制内存
//vector本质是动态管理连续内存的容器,其核心是通过三个内存指针(迭代器)来控制内存块:
//_start:指向内存块的起始位置(第一个元素的地址)
//_finish:指向有效元素的末尾(最后一个元素的下一位)
//_end_of_storage:指向内存块的,末尾(容量的边界)
namespace Myvector
{
//template<>是模板,T是占位符,用它替代具体的int、string、double类型
template<class T>
class vector
{
public:
typedef T* iterator; //将T*重命名为iterator(迭代器),也就是对原生指针的封装
typedef const T* const_iterator;
//通过这三个指针,可以间接计算有效元素的个数(size),容量(capacity),就不用像数组那样麻烦
size_t size()const
{
return _finish - _start; //有效元素个数
}
size_t capacity()const
{
return _end_of_storage - _start; //容量
}
//无参构造
vector()
// _start:指向内存块的起始位置(第一个元素的地址)
//_finish:指向有效元素的末尾(最后一个元素的下一位)
//_end_of_storage:指向内存块的,末尾(容量的边界)
:_start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
//这里写不写初始化列表都无所谓,因为已经有了缺省值
{
}
//v1(v2)
//拷贝构造---v2拷贝给v1
//reserve:仅扩容,不初始化元素
vector(const vector<T>& v) //引用,vector<T>是类型
{
reserve(v.size()); //提前开好空间,避免后面push_back不断扩容
for (auto& e : v)
{
push_back(e);
}
}
//清空数据clear
void clear()
{
_finish = _start;
//只清空数据不改变空间大小
}
//v3 = v1
//赋值运算符重载
//传统写法
//vector<T>& operator=(const vector<T>& v)
//{
// if (this != &v)//地址相同则说明在同一块空间不需要赋值
// {
// clear();
// reserve(v.size());
// for (auto& e : v)
// {
// push_back(e);
// }
// }
// return *this;
//}
void swap(vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_end_of_storage, v._end_of_storage);
}
//现代写法
vector<T>& operator=(vector<T> v)
//需要注意的是:现代写法的形参不能和传统写法一样是引用传参
//因为swap会对形参和*this进行内容交换,如果是引用传参则外部的实参也会受到影响
//而传值传参时形参不管怎么改变出了函数就会被销毁,不会影响实参
//而且如果*this没有初始化的话则会更加危险
{
if (this != &v)//地址相同则说明在同一块空间不需要赋值
{
swap(v);
}
return *this;
}
//析构
~vector()
{
if (_start) //如果_start不就是空则不需要delete
{
delete[] _start;
_start = _finish = _end_of_storage = nullptr;
}
}
void reserve(size_t n)
{
if (n > capacity())
{
size_t old_size = size(); //先把保存原大小
T* tmp = new T[n];
//memcpy(tmp, _start, size() * sizeof(T));
//对于内置类型没有问题,但是自定义类型就会进行浅拷贝而出现问题
for (size_t i = 0; i < old_size; i++)
{
tmp[i] = _start[i];
}//深拷贝
delete[] _start; //释放掉原数组,还没给他赋新值,_finish 仍是原数组的指针,size()就不能用了
_start = tmp; //赋新值了,_start指向了新数组
_finish = _start + old_size; //finish要想不是空指针就得用原大小(old size)+新的_start
_end_of_storage = _start + n;
////_finish 会空指针版本
//if (n > capacity())
//{
// T* tmp = new T[n];
// mecoy(tmo, _start, size() * sizeof(T));
// delete[] _start;
// _start = tmp;
// _finish = _start + size();
// _end_storage=_start+n;
//}
}
}
//resize(n,val)会将size调整为n,多余元素销毁,不足则用val填充
void resize(size_t n, T val = T())
//=T()表示:如果调用时不写第二个参数,就要用T类型的默认构造对象来填充
//由于val类型是T,此时就不能像以前用0来充当缺省值,如何理解这句话呢?
// 当T是int类型时,T()就是0
// 当T是string\vector这种自定义类型时,0不能用来初始化,必须用T()调用他自己的默认构造函数
{
if (n < size())
{
_finish = _start + n;
}
else
{
if (n > capacity())
{
reserve(n);
}
while (_finish < _start + n) //元素不足时
{
*_finish = val;
_finish++;
}
}
}
T& operator[](size_t i)
{
assert(i < size());
return _start[i];
}
const T& operator[](size_t i) const
{
assert(i < size());
return _start[i];
}
//尾插push_back
void push_back(const T& x)
{
if (_finish == _end_of_storage)
{
reserve(capacity() == 0 ? 4 : 2 * capacity());
}
*_finish = x;
_finish++;
}
//判空
bool empty()
{
return _start == _finish;
}
//尾删pop_back
void pop_back()
{
assert(!empty());
--_finish;
}
//插入insert
void insert(iterator pos, const T& x)
{
assert(pos >= _start && pos < _finish);
if (_finish == _end_of_storage)
{
size_t len = pos - _start; //提前获取偏移量
reserve(capacity() == 0 ? 4 : 2 * capacity());
pos = _start + len; //对pos进行修正(也就是重新获取迭代器)
}
iterator end = _finish - 1; //end指向的位置是原数组最后一位有效数字的位置
while (end >= pos)
{
*(end + 1) = *end; //从后往前赋值,避免后面的值被前面的值覆盖
end--;
}
*pos = x;
_finish++;
}
//删除erase
iterator erase(iterator pos)
{
assert(pos >= _start && pos < _finish);
iterator it = pos + 1;
while (it != end())
{
*(it - 1) = *it; //从前往后赋值
it++;
}
_finish--;
return pos;
}
//迭代器
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator begin() const
{
return _start;
}
const_iterator end() const
{
return _finish;
}
//补充接口
//迭代器区间构造
//类模板的成员函数,也可以继续是函数模板
template<class InputIterator>
vector(InputIterator first, InputIterator last)
//不用iterator迭代器的好处是:不仅限于传vector的迭代器,其他容器的迭代器均可以传入
{
while (first != last)
{
push_back(*first);
first++;
}
}
//n个val构造
vector(size_t n, const T& val = T())
{
reserve(n);
for (size_t i = 0; i < n; i++)
{
push_back(val);
}
}
private:
iterator _start = nullptr;//数据起始位置
iterator _finish = nullptr;//有效数据的结束位置
iterator _end_of_storage = nullptr;//总空间大小的结尾位置
};
//迭代器遍历
template <class T>
void print_vector(const vector<T>& v)
{
//vector<T>::const_iterator it = v.begin(); //error
//规定:没有实例化的类模板编译器是不能在里面获取东西。
//编译器无法区分 const_iterator 究竟是我们 typedef 出的类型还是静态成员变量
typename vector<T>::const_iterator it = v.begin();
//auto it = v.begin(); //用auto就可以省去这些麻烦了,可以直接自动推导出对应类型
while (it != v.end())
{
cout << *it << " ";
it++;
}
cout << endl;
}
}
🐾 Test.cpp
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include "vector.h"
//增删
void test_vector1()
{
Myvector::vector<int> v1;
//v1.reserve(v1.capacity() == 0 ? 4 : 2 * v1.capacity());
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
//遍历
for (size_t i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";////1 2 3 4 5
}
//print_vector(v1); //1 2 3 4 5----替代上面一整段
cout << endl;
//尾删
v1.pop_back();
print_vector(v1); //1 2 3 4
//insert插入---在第2个位置插入
v1.insert(v1.begin() + 1, 5);
print_vector(v1); //1 5 2 3 4
//迭代器失效:扩容-----在第3个位置插入
Myvector::vector<int>::iterator p = v1.begin() + 2;
v1.insert(p, 6);
////当 insert 如果扩容了,则第一个实参迭代器就会因为_start被delete而失效(变成野指针)
////此时就不能再次访问,如果需要访问就需要重新更新失效迭代器的值
p = v1.begin() + 2;
*p *= 10; //6*10,上面的也会变成60
print_vector(v1); //1 5 60 2 3 4
//erase删除
v1.erase(v1.begin() + 2);
print_vector(v1); //1 5 2 3 4
//迭代器失效:删除
//删除所有偶数
auto it = v1.begin();
while (it != v1.end())
{
if (*it % 2 == 0)
{
it = v1.erase(it);// 用返回值更新迭代器
}
else
{
it++;
}
}
print_vector(v1);
}
//int main()
//{
// test_vector1();
// return 0;
//}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void test_vector2()
{
////int型
Myvector::vector<int> v1;
//尾插
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
//拷贝构造
auto v2 = v1;
print_vector(v1); //1 2 3
print_vector(v2); //1 2 3
Myvector::vector<int> v3;
v3 = v1; //赋值运算符重载
print_vector(v3); //1 2 3
//自定义类型
Myvector::vector<string> v;
v.push_back("111");
v.push_back("222");
v.push_back("333");
v.push_back("444");
print_vector(v);
v.push_back("555"); //此时需要扩容
print_vector(v);
}
//int main()
//{
// test_vector2();
// return 0;
//}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void test_vector3()
{
Myvector::vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
print_vector(v1); //1 2 3 4 5
//迭代器区间构造
Myvector::vector<int> v2(v1.begin() + 1, v1.begin() + 4); //[第2个位置,第4个位置)
print_vector(v2); //2 3 4
//n个val构造
Myvector::vector<int> v3(10);
print_vector(v3); //0 0 0 0 0 0 0 0 0 0
Myvector::vector<int> v4(10u, 1); //10u的类型就是size_t,就不会误调用迭代器区间构造,元素是1
print_vector(v4); //1 1 1 1 1 1 1 1 1 1
}
//int main()
//{
// test_vector3();
//
// return 0;
//}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
//int main()
//{
// //test_vector1();
// //test_vector2();
// //test_vector3();
// int a = int(); //无参则为0
// int b = int(1);
// int c(b); //用变量b的值初始化c
// cout << a << " " << b << " " << c << " " << endl;//0 1 1
// return 0;
//}
- 欢迎留言交流
- 期待你的评论与建议
- 留下你的想法吧

谢谢你看到这里呀
如果喜欢这篇内容,点个关注,下次更新不迷路✨
👍 点赞 ⭐ 收藏 💬 评论

