STL之vector篇(下)(手撕底层代码,从零实现vector的常用指令,深度剖析并优化其核心代码)

news2024/11/23 21:29:14

文章目录

    • 1.基本结构与初始化
      • 1.1 空构造函数的实现与测试
      • 1.2 带大小和默认值的构造函数
      • 1.3 使用迭代器范围初始化的构造函数(建议先看完后面的reserve和push_back)
      • 1.4 拷贝构造函数
      • 1.5 赋值操作符的实现(深拷贝)
      • 1.6 析构函数
      • 1.7 `begin` 与 `end` 迭代器
    • 2. 容量管理
      • 2.1 `reserve`函数:实现动态扩容
      • 2.2 `resize`函数:改变大小
    • 3. 元素插入与删除
      • 3.1 `push_back`函数:尾插元素
      • 3.2 `pop_back`函数:尾删元素
      • 3.3 `insert`函数:在指定位置插入元素
      • 3.4 `erase`函数:删除指定位置的元素
    • 4.全部代码实现
      • 4.1 头文件
      • 4.2 源文件


前言:

在编程的浩瀚星空中,数据结构如同指引方向的星辰,它们不仅是构建算法与程序大厦的基石,更是解决复杂问题、优化性能的关键所在。其中,vector作为C++标准模板库(STL)中的一颗璀璨明珠,凭借其灵活、高效的特点,在软件开发中占据了举足轻重的地位。

vector,即向量容器,是一种能够存储任意类型对象的动态数组。它封装了动态数组的所有特性,包括自动的内存管理、灵活的元素访问方式以及高效的随机访问性能,同时还提供了丰富的成员函数来支持元素的插入、删除、遍历等操作。与静态数组相比,vector的最大优势在于其大小可以动态变化,无需程序员手动管理内存,极大地简化了编程复杂度,提高了代码的安全性和可维护性。
本文旨在深入探讨vector的内部机制、使用技巧及最佳实践,帮助读者全面了解并掌握这一强大的数据结构。我们将从vector的基本概念和特性出发,逐步深入到其内存管理策略、迭代器使用、元素操作、性能优化等多个方面。同时,结合实际应用场景,展示vector在解决各种编程问题时的独特魅力和高效性。

无论你是C++编程的初学者,还是希望提升编程技能的老手,本文都将为你提供宝贵的参考和实用的指导。让我们一起踏上这场关于vector的探索之旅,解锁C++编程的新世界,感受数据结构的魅力与力量。

1.基本结构与初始化

1.1 空构造函数的实现与测试

  • 实现一个空的vector,不分配任何内存。
  • 测试是否创建了容量为0的vector

实现代码:

namespace xny {
    template<class T>
    class vector {
    public:
        typedef T* iterator;

        vector() {}

        size_t size() const {return _finish - _start;}
        size_t capacity() const {return _endofstorage - _start;}
        bool empty() const {return _start == _finish;}

    private:
        iterator _start = nullptr;
        iterator _finish = nullptr;
        iterator _endofstorage = nullptr;
    };
}

测试样例:

void testvector1() {
    xny::vector<int> v;
    assert(v.size() == 0);  // 验证大小
    assert(v.capacity() == 0);  // 验证容量
    assert(v.empty());  // 验证是否为空
    cout << "testvector1 passed" << endl;
}

int main()
{
    testvector1();
    return 0;
}

输出:

testvector1 passed

1.2 带大小和默认值的构造函数

  • 初始化一个给定大小的vector,并使用默认值填充。
  • 测试构造后大小、容量是否符合要求。

实现代码:

namespace xny {
    template<class T>
    class vector {
    public:
        typedef T* iterator;

        vector() {}

        vector(size_t n, const T& val = T()){    // 缺省参数用T类型的匿名对象
            _start = new T[n];
            _finish = _start + n;
            _endofstorage = _finish;
            for (size_t i = 0; i < n; i++) {
                _start[i] = val;  // 填充默认值
            }
        }

        T& operator[](size_t pos) { return _start[pos]; }

        size_t size() const {return _finish - _start;}
        size_t capacity() const {return _endofstorage - _start;}
        bool empty() const {return _start == _finish;}

    private:
        iterator _start = nullptr;
        iterator _finish = nullptr;
        iterator _endofstorage = nullptr;
    };
}

测试样例:

void testvector2(){
    xny::vector<int> v(4, 1);
    assert(v.size() == 4);  // 验证大小
    assert(v.capacity() == 4);  // 验证容量
    assert(!v.empty());  // 验证是否为空
    for (size_t i = 0; i < 4; ++i) {
        assert(v[i] == 1);  // 验证默认值
    }
    cout << "testvector2 passed" << endl;
}

int main()
{
    testvector3();

    return 0;
}

输出:

testvector2 passed

1.3 使用迭代器范围初始化的构造函数(建议先看完后面的reserve和push_back)

【思考】:

  • 假设我用上述代码去实现以下样例会发生什么呢?
void testvector3() {
    int arr[] = { 1, 2, 3, 4, 5 };
    xny::vector<int> v(arr, arr + 5); // 使用迭代器范围初始化构造函数
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

【结果】:

  • 这时我们意识到可能需要重新定义一个构造函数,并且这个构造函数可以使用迭代器范围初始化。

添加代码如下:

namespace xny {
    template<class T>
    class vector {
    public:
        typedef T* iterator;

        iterator begin(){ return _start; }
        iterator end(){ return _finish; }

        vector() {}

        vector(size_t n, const T& val = T()){    // 缺省参数用T类型的匿名对象
            _start = new T[n];
            _finish = _start + n;
            _endofstorage = _finish;
            for (size_t i = 0; i < n; i++) {
                _start[i] = val;  // 填充默认值
            }
        }
        
		// 使用迭代器范围初始化的构造函数
        template<class InputIterator>
        vector(InputIterator first, InputIterator last){
            while (first != last)	// 迭代器区间左闭右开
            {
                push_back(*first);
                ++first;
            }
        }

        void reserve(size_t n){
            if (n > capacity()){
                size_t sz = size();
                T* tmp = new T[n];
                if (_start){
                    for (size_t i = 0; i < sz; i++){
                        tmp[i] = _start[i];
                    }
                    delete[] _start;
                }

                _start = tmp;
                _finish = _start + sz;
                _endofstorage = _start + n;
            }
        }

        void push_back(const T& x){
            if (_finish == _endofstorage){
                size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
                reserve(newcapacity);
            }

            *_finish = x;
            ++_finish;
        }

        T& operator[](size_t pos) { return _start[pos]; }

        size_t size() const {return _finish - _start;}
        size_t capacity() const {return _endofstorage - _start;}
        bool empty() const {return _start == _finish;}

    private:
        iterator _start = nullptr;
        iterator _finish = nullptr;
        iterator _endofstorage = nullptr;
    };
}

测试样例:

void testvector3() {
    int arr[] = { 1, 2, 3, 4, 5 };
    xny::vector<int> v1(arr, arr + 5); // 使用迭代器范围构造函数
    for (auto e : v1){
        cout << e << " ";
    }
    cout << endl;

    string str("hello world");
    xny::vector<char> v2(str.begin(), str.end());
    for (auto e : v2) {
        cout << e << " ";
    }
    // 这里我们用两种不同类型的迭代器进行测试
}

输出:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

【思考】:

  • 怎么回事呢?编译器又报错了,并且这次报的错比较模糊,于是我们可以直接搜索error C2100,看看编译示例:

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

【解释】:

  • 结合以上所有的编译报错我们终于发现错误的原因可能是非法寻址了,于是再次进行改进添加代码如下:
vector(int n, const T& val = T()) {    
    _start = new T[n];
    _finish = _start + n;
    _endofstorage = _finish;
    for (size_t i = 0; i < n; i++) {
        _start[i] = val; 
    }
}

输出:

1 2 3 4 5
h e l l o   w o r l d

1.4 拷贝构造函数

  • 实现vector的拷贝构造函数。
  • 测试拷贝后的vector是否完全复制原来的内容和容量。

实现代码:

namespace xny {
    template<class T>
    class vector {
    public:
        typedef T* iterator;
        
        vector() {}
        
        vector(size_t n, const T& val = T()){    
            _start = new T[n];
            _finish = _start + n;
            _endofstorage = _finish;
            for (size_t i = 0; i < n; i++) {
                _start[i] = val;  
            }
        }
        
        vector(const vector<T>& v){
            size_t sz = v.size();   
            _start = new T[capacity()];
            for (size_t i = 0; i < sz; i++) {
                _start[i] = v._start[i];
            }

            _finish = _start + sz;
            _endofstorage = _start + v.capacity();
        }

        T& operator[](size_t pos) { return _start[pos]; }

        size_t size() const {return _finish - _start;}
        size_t capacity() const {return _endofstorage - _start;}
        bool empty() const {return _start == _finish;}

    private:
        iterator _start = nullptr;
        iterator _finish = nullptr;
        iterator _endofstorage = nullptr;
    };
}

测试样例:

void testvector4() {
    xny::vector<int> v1(5, 10);
    xny::vector<int> v2(v1);
    assert(v2.size() == 5);  // 验证大小
    assert(v2.capacity() == 5);  // 验证容量
    for (size_t i = 0; i < 5; ++i) {
        assert(v2[i] == 10);  // 验证数据拷贝
    }
    std::cout << "testvector4 passed" << std::endl;
}

int main()
{
    testvector4();

    return 0;
}

输出:

testvector4 passed

1.5 赋值操作符的实现(深拷贝)

  • 实现赋值操作符重载。
  • 测试两个vector赋值后,是否正确拷贝了内容和容量。

实现代码:

namespace xny {
    template<class T>
    class vector {
    public:
        typedef T* iterator;
        
        vector() {}

        vector(size_t n, const T& val = T()){    
            _start = new T[n];
            _finish = _start + n;
            _endofstorage = _finish;
            for (size_t i = 0; i < n; i++) {
                _start[i] = val;  
            }
        }
        
		// 自定义一个swap函数方便拷贝
        void swap(const vector<T> v){
            std::swap(_start, v._start);
            std::swap(_finish, v._finish);
            std::swap(_endofstorage, v._endofstorage);
        }
		
        // 赋值运算符重载
        vector<T>& operator=(const vector<T>& v){
            swap(v);
            return *this;
        }

        T& operator[](size_t pos) { return _start[pos]; }

        size_t size() const {return _finish - _start;}
        size_t capacity() const {return _endofstorage - _start;}
        bool empty() const {return _start == _finish;}

    private:
        iterator _start = nullptr;
        iterator _finish = nullptr;
        iterator _endofstorage = nullptr;
    };
}

【说明】:

  • **传值参数:**通过传递 vector<T> 的值作为参数,创建一个临时对象 v。调用拷贝构造函数时自动执行拷贝,然后在赋值操作中与现有对象交换内容。传值是安全的,避免了手动内存管理问题。
  • **swap函数:**通过交换数据成员,避免手动内存释放,简化代码逻辑。交换后的临时对象 v 离开作用域时自动销毁,保证资源释放。

测试样例:

void testvector5() {
    xny::vector<int> v1(5, 10);
    xny::vector<int> v2 = v1;  // 赋值操作
    assert(v2.size() == 5);  // 验证大小
    assert(v2.capacity() == 5);  // 验证容量
    for (size_t i = 0; i < 5; ++i) {
        assert(v2[i] == 10);  // 验证数据拷贝
    }
    std::cout << "testvector5 passed" << std::endl;
}

int main()
{
    testvector5();

    return 0;
}

输出:

testvector5 passed

1.6 析构函数

实现代码:

~vector()
{
	if (_start)
	{
		delete[] _start;
		_start = _finish = _endofstorage = nullptr;
	}
}

【注意】

  • 为了避免内存泄露的问题,上述代码全部都需要添加析构函数。

1.7 beginend 迭代器

【解释】:

  • begin 函数返回指向 vector 起始位置的迭代器(即指向第一个元素)。
  • end 函数返回指向 vector 末尾的迭代器(即指向最后一个元素的下一个位置)。
  • 两者结合可以用于遍历 vector 中的元素。

添加代码:

iterator begin(){
	return _start;
}

iterator end(){
	return _finish;
}

2. 容量管理

2.1 reserve函数:实现动态扩容

  • 实现reserve函数,测试在容量不足时是否能正确扩展。

添加代码:

void reserve(size_t n) {
    if (n > capacity()) {
        size_t sz = size();
        T* tmp = new T[n];

        if (_start) {
            for (size_ t i = 0; i < sz; i++) {
                tmp[i] = _start[i];
            }
            delete[] _start;
        }

        _start = tmp;
        _finish = _start + sz;
        _endofstorage = _start + n;
    }
}

【注意】:

  • T是自定义类型时,依次调用数组每个对象的析构函数,再释放整个空间

  • 原来for循坏中使用的是memcpy(tmp, _start, sizeof(T) * sz);但是vector是深拷贝,但是vector空间上存的对象是string数组,使用memcpy导致string对象的浅拷贝

  • 解决方案:T是string这样深拷贝的类,调用的是string赋值重载,实现的是string对象的深拷贝

测试用例:

void testvector6() {
    xny::vector<int> v(5, 10);
    v.reserve(10);  // 预留容量
    assert(v.capacity() == 10);  // 验证容量扩展
    for (size_t i = 0; i < 5; ++i) {
        assert(v[i] == 10);  // 验证数据保持不变
    }
    std::cout << "testvector6 passed" << std::endl;
}

int main()
{
    testvector6();

    return 0;
}

输出:

testvector6 passed

2.2 resize函数:改变大小

  • 实现resize函数,测试增加或减少vector大小,如果增加,用特定字符暂时覆盖。

添加代码:

void resize(size_t n, const T& val = T()) {
    if (n < size()) {
        _finish = _start + n;
    }
    else {
        // 扩容n
        reserve(n);

        // 传值
        while (_finish != _start + n) {
            *_finish = val;
            ++_finish;
        }
    }
}

测试用例:

void testvector7() {
    xny::vector<int> v(5, 10);
    v.resize(8, 20);  // 扩展大小并填充新值
    assert(v.size() == 8);  // 验证扩展后大小
    for (size_t i = 0; i < 5; ++i) {
        assert(v[i] == 10);  // 验证原值不变
    }
    for (size_t i = 5; i < 8; ++i) {
        assert(v[i] == 20);  // 验证新值
    }
    std::cout << "testvector7 passed" << std::endl;
}

int main()
{
    testvector7();

    return 0;
}

输出:

testvector7 passed

3. 元素插入与删除

3.1 push_back函数:尾插元素

【实现步骤】:

    1. 检查容量是否足够,若不足则扩容(通常容量加倍)。
    1. 将新元素插入到当前末尾。
    1. 更新_finish指针,指向新的末尾。

添加代码:

void push_back(const T& val){
    if (_finish == _endofstorage) {
        size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;  // 采用2倍扩容
        reserve(newcapacity);
    }

    *_finish = val;
    ++_finish;
}

优化版本:

void push_back(const T& x){
	insert(end(), x);
}

测试用例:

void testvector8() {
    xny::vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);

    assert(v.size() == 3);  // 验证插入后的大小
    assert(v.capacity() >= 3);  // 验证容量是否自动扩展
    assert(v[0] == 1 && v[1] == 2 && v[2] == 3);  // 验证插入的元素是否正确

    std::cout << "testvector9 passed" << std::endl;
}

int main()
{
    testvector8();

    return 0;
}

输出:

testvector8 passed

3.2 pop_back函数:尾删元素

【实现步骤】:

    1. _finish指针向前移动一位,即删除最后一个元素。
    1. 不释放空间。

添加代码:

void pop_back(const T& val) {
    assert(_finish != _start);  // 确保vector非空
    --_finish;  // 逻辑删除最后一个元素
}

优化版本:

void pop_back(){
	erase(--end());
}

测试用例:

void testvector9() {
    xny::vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.pop_back();

    assert(v.size() == 2);  // 验证删除后的大小
    assert(v[0] == 1 && v[1] == 2);  // 验证剩余元素是否正确

    std::cout << "testvector9 passed" << std::endl;
}

int main()
{
    testvector9();

    return 0;
}

输出:

testvector9 passed

3.3 insert函数:在指定位置插入元素

【实现步骤】:

    1. 检查容量是否足够,不足时扩容。
    1. 将插入位置及其后的元素整体向后移动。
    1. 将新元素插入指定位置。
    1. 更新_finish指针。

添加代码:

iterator insert(iterator pos, const T& val) {
    // 断言判断pos的有效性
    assert(pos >= _start && pos <= _finish);

    if (_finish == _endofstorage) {
        // 用临时变量存指定位置到起点的长度
        size_t len = pos - _start;
        size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;  // 采用2倍扩容
        reverse(newcapacity);

        // 解决pos迭代器失效问题
        pos = len + _start;
    }

    // 将插入位置及其后的元素整体向后移动。
    iterator end = _finish - 1;
    while (end >= pos) {
        *(end + 1) = *end;
        --end;
    }

    *pos = val;
    ++_finish;

    return pos;
}

测试用例:

void testvector10() {
    xny::vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(4);

    v.insert(v.begin() + 2, 3);  // 在第2个位置插入3

    assert(v.size() == 4);  // 验证插入后的大小
    assert(v[0] == 1 && v[1] == 2 && v[2] == 3 && v[3] == 4);  // 验证插入的元素是否正确

    std::cout << "testvector8 passed" << std::endl;
}

int main()
{
    testvector10();

    return 0;
}

输出:

testvector10 passed

【问题】:

  • 扩容之后,pos迭代器可能会发生改变,所以不能用原来的pos

3.4 erase函数:删除指定位置的元素

【实现步骤】:

    1. erase位置之后的元素向前移动一位。
    1. 更新_finish指针。

添加代码:

iterator erase(iterator pos) {
    // 断言判断pos的有效性
    assert(pos >= _start && pos <= _finish);

    iterator it = pos + 1;
    while (it != _finish) {
        *(it - 1) = *it;
        ++it;
    }
    --_finish;

    return pos;
}

测试用例:

void testvector11() {
    xny::vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);

    v.erase(v.begin() + 2);  // 删除第2个元素

    assert(v.size() == 3);  // 验证删除后的大小
    assert(v[0] == 1 && v[1] == 2 && v[2] == 4);  // 验证删除后的元素顺序

    std::cout << "testvector11 passed" << std::endl;
}

int main()
{
    testvector11();

    return 0;
}

输出:

testvector11 passed

4.全部代码实现

【注意】

  • 以下代码会提供常量和普通变量的两种函数或者迭代器。

4.1 头文件

#pragma once

#include<assert.h>
using namespace std;

namespace xny
{
	template<class T>
	class vector
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;

		iterator begin()
		{
			return _start;
		}

		iterator end()
		{
			return _finish;
		}

		const_iterator begin() const
		{
			return _start;
		}

		const_iterator end() const
		{
			return _finish;
		}

		vector(size_t n, const T& val = T())
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{
			resize(n, val);
		}

		// 解决vector<int> v(10, 1)
		vector(int n, const T& val = T())
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{
			resize(n, val);
		}

		template<class InputIterator>
		vector(InputIterator first, InputIterator last)
		{
			while (first != last)	// 迭代器区间左闭右开
			{
				push_back(*first);
				++first;
			}
		}

		vector()
		{}

		vector(const vector<T>& v)
		{
			size_t sz = v.size();
			_start = new T[v.capacity()];
			// memcpy(_start, v._start, sizeof(T) * v.size());
			for (size_t i = 0; i < sz; i++)
			{
				_start[i] = v._start[i];
			}

			_finish = _start + sz;
			_endofstorage = _start + v.capacity();
		}

		void swap(vector<T>& v)
		{
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_endofstorage, v._endofstorage);
		}

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

		~vector()
		{
			if (_start)
			{
				delete[] _start;
				_start = _finish = _endofstorage = nullptr;
			}
		}


		void reserve(size_t n)
		{
			if (n > capacity())
			{
				size_t sz = size();
				T* tmp = new T[n];
				if (_start)
				{
					for (size_t i = 0; i < sz; i++)
					{
						tmp[i] = _start[i];
					}
					delete[] _start;
				}

				_start = tmp;
				_finish = _start + sz;
				_endofstorage = _start + n;
			}
		}

		void resize(size_t n, const T& val = T())	// T类型的匿名对象
		{
			if (n < size())
			{
				_finish = _start + n;
			}
			else
			{
				reserve(n);

				while (_finish != _start + n)
				{
					*_finish = val;
					++_finish;
				}
			}
		}

		void push_back(const T& x)
		{
			/*if (_finish == _endofstorage)
			{
				size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newcapacity);
			}

			*_finish = x;
			++_finish;*/
			insert(end(), x);
		}

		void pop_back()
		{
			erase(--end());
		}

		size_t capacity() const
		{
			return _endofstorage - _start;
		}

		size_t size() const
		{
			return _finish - _start;
		}

		T& operator[](size_t pos)
		{
			assert(pos < size());

			return _start[pos];
		}

		const T& operator[](size_t pos) const
		{
			assert(pos < size());

			return _start[pos];
		}

		iterator insert(iterator pos, const T& x)
		{
			assert(pos >= _start && pos <= _finish);

			if (_finish == _endofstorage)
			{
				size_t len = pos - _start;

				size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newcapacity);

				// 解决pos迭代器失效问题
				pos = _start + len;
			}

			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}

			*pos = x;
			++_finish;

			return pos;
		}

		iterator erase(iterator pos)
		{
			assert(pos >= _start && pos < _finish);

			iterator it = pos + 1;
			while (it != _finish)
			{
				*(it - 1) = *it;
				++it;
			}
			--_finish;

			return pos;
		}

	private:
		iterator _start = nullptr;
		iterator _finish = nullptr;
		iterator _endofstorage = nullptr;
	};

	void print(const vector<int>& v)
	{
		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;
	}

	void test_vector1()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(5);

		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;

		for (size_t i = 0; i < v1.size(); i++)
		{
			v1[i]++;
		}

		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;

		print(v1);
	}

	void test_vector2()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(5);
		v1.push_back(5);
		v1.push_back(5);
		v1.push_back(5);

		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;

		v1.insert(v1.begin(), 100);

		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;

		/*vector<int>::iterator p = v1.begin() + 3;
		v1.insert(p, 300);*/

		xny::vector<int>::iterator p = v1.begin() + 3;
		//v1.insert(p+3, 300);

		// insert以后迭代器可能会失效(扩容)
		// 记住,insert以后就不要使用这个形参迭代器了,因为他可能失效了
		v1.insert(p, 300);

		// 高危行为
		// *p += 10;

		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;
	}

	void test_vector3()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(5);

		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;

		// v1.erase(v1.begin());

		auto it = v1.begin() + 4;
		v1.erase(it);

		// erase之后,迭代器失效了,不能访问
		// vs进行强制检查,访问会直接报错
		cout << *it << endl;
		++it;
		cout << *it << endl;

		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;
	}

	void test_vector4()
	{
		vector<int> v;
		v.resize(10, 0);

		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;

	}

	void test_vector5()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(5);

		vector<int> v2(v1);

		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;

		vector<int> v3 = v1;
		for (auto e : v3)
		{
			cout << e << " ";
		}
		cout << endl;
	};

	void test_vector6()
	{
		vector<string> v;
		v.push_back("11111");
		v.push_back("22222");
		v.push_back("33333");
		v.push_back("44444");
		v.push_back("55555");

		// 自定义类型最好加引用
		for (auto& e : v)
		{
			cout << e << " ";
		}
		cout << endl;

		vector<string> v1(v);
		for (auto& e : v1)
		{
			cout << e << " ";
		}
		cout << endl;
	}

	void test_vector7()
	{
		vector<int> v(10u, 1);
		vector<string> v1(10, "111");

		// vector<int> v2(10, 1);

	}
}

4.2 源文件

#include"vector.h"
#include <bits/stdc++.h>
using namespace std;

int main()
{
	xny::test_vector7();
	// ...其他测试
    
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2168748.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

jQuery——层次选择器

1、层次选择器&#xff1a;查找子元素&#xff0c;后代元素&#xff0c;兄弟元素的选择器。 ancestor descendant&#xff1a;在给定的祖先元素下匹配所有的后代元素 parent > child&#xff1a;在给定的父元素下匹配所有的子元素 prev next&#xff1a;匹配所有紧接在…

每日一练:二叉树的右视图

199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 一、题目要求 给定一个二叉树的 根节点 root&#xff0c;想象自己站在它的右侧&#xff0c;按照从顶部到底部的顺序&#xff0c;返回从右侧所能看到的节点值。 示例 1: 输入: [1,2,3,null,5,null,4] 输出: [1,3,…

超详细的 pytest教程 之前后置方法和 fixture 机制

前言 这一篇文章专门给大家讲解pytest中关于用例执行的前后置步骤处理,pytest中用例执行的前后置处理既可以通过测试夹具(fixtrue)来实现&#xff0c;也可以通过xunit 风格的前后置方法来实现。接下来我们一起看看如何具体使用。 一、xunit 风格的前后置方法 1、函数用例的前…

基于STM32的智能家庭安全监控系统

目录 引言项目背景环境准备 硬件准备软件安装与配置系统设计 系统架构关键技术代码示例 传感器数据采集摄像头监控与数据处理实时报警功能实现应用场景结论 1. 引言 智能家庭安全监控系统使用嵌入式设备&#xff0c;如STM32微控制器&#xff0c;来实时监控家庭环境。通过集成…

[教程]如何在iPhone上启用中国移动/联通/电信RCS消息

目前 苹果已经在 iOS 18 中带来 RCS 富媒体消息的支持&#xff0c;该消息基于网络传递&#xff0c;用户可以通过 RCS 免费将消息发送到其他 iPhone 或 Android 设备。在苹果面向测试版用户推出的 iOS 18.1 Beta 版中&#xff0c;中国网络运营商包括中国移动、中国联通、中国电信…

文献笔记 - Ground effect on rotorcraft unmanned aerial vehicles: a review

这篇博文是自己看文章顺手做的笔记 只是简单翻译和整理 仅做个人参考学习和分享 如果作者看到觉得内容不妥请联系我 我会及时处理 本人非文章作者&#xff0c;文献的引用格式如下&#xff0c;原文更有价值 摘要—— 收集和讨论小型多旋翼无人机受地面效应的影响&#xff0c;…

阿b的弹幕如何获取?这个可以帮到你!

弹幕 前几天&#xff0c;做了一个b站弹幕的爬取&#xff0c;只需要输入一个bv号&#xff0c;就可以查看这个视频的弹幕&#xff0c;并且提供了一种可以写入到文件的方法。但是有人反应&#xff0c;这种使用仍然非常困难&#xff0c;应该提供一个更加友好的用户界面。 因此本期…

共享单车轨迹数据分析:以厦门市共享单车数据为例(八)

副标题&#xff1a;基于POI数据的站点综合评价——以厦门市为例&#xff08;三&#xff09; 什么是优劣解距离法&#xff08;TOPSIS&#xff09;&#xff1f; 优劣解距离法&#xff08;Technique for Order Preference by Similarity to Ideal Solution&#xff0c;简称TOPSI…

借用连接2-得到主库或从库池子连接

二、借用连接--AbstractRoutingDataSource类 目的&#xff1a;基于look up data&#xff0c;然后从目标数据源借用连接 注look up key确定走主 or 从数据库连接池代码开发&#xff1a; 1.定义子类继承AbstractRoutingDataSource&#xff0c;并覆写determineCurrentLookupKey方…

Vue3+Element-UI Plus登录静态页

<script setup> import {reactive, ref} from "vue";const formRefref() const formModelreactive({username:,password: }) const formRulesreactive({username:[{required:true,message:请输入账号,trigger:blur}],password:[{required:true,message:请输入密…

深圳前湾地铁附近的13元一份的工地盒饭

因为深圳前海这边有很多工地&#xff0c;所以也存在很多的工地餐厅。发现价格出奇统一&#xff0c;都是13元一份。主打一个量大管饱还下饭&#xff0c;每次都吃得有些撑。前海写字楼下的底商也很多打工人的干饭餐厅&#xff0c;但是工作餐均价都要30。如果不在餐厅吃&#xff0…

高通AI应用程序开发3:网络模型(一)

1. 支持的网络模型 Qualcomm神经处理SDK支持下表所列的网络模型。 有关支持的运行时和单个图层类型的限制和约束的详细信息&#xff0c;请参阅 限制 。 GPU运行时中支持的所有层对两种GPU模式都有效&#xff1a;GPU_FLOAT32_16_HYBRID和GPU_FLAAT16。GPU_FLOAT32_16_HYBRID-…

3分钟!手把手教你学会如何无损放大图片

我们常常遇到需要放大图片却又不希望损失画质的尴尬境地。无论是为了打印大幅海报、在线展示高清细节&#xff0c;还是想要修复珍贵的老照片&#xff0c;无损放大图片成为了许多人的迫切需求。下面给大家分享一款最新无损放大图片软件&#xff0c;高效且实用&#xff0c;一起来…

VMware搭建DVWA靶场

目录 1.安装phpstudy 2.搭建DVWA 本次搭建基于VMware16的win7系统 1.安装phpstudy 下载windows版本&#xff1a;小皮面板-好用、安全、稳定的Linux服务器面板&#xff01; 安装后先开启mysql再开启apache&#xff0c;遇到mysql启动不了的情况&#xff0c;最后重装了phpstud…

如何在Windows和Linux之间实现粘贴复制

第一步 sudo apt-get autorremove open-vm-tools第二步 sudo apt-get update第三步 sudo apt-get install open-vm-tools-desktop第四步 一直按Y&#xff0c;希望执行 Y第四步 重启 reboot然后可以实现粘贴复制。

国内外AI大模型对比,国产AI的优势是什么?非常详细收藏我这一篇就够了

AI正在以惊人的速度改变各行各业的运作方式。 热点趋势解读之AI系列&#xff0c;将通过多篇文章探讨如何利用AI驱动创新、提升效率&#xff0c;并为未来的商业和社会发展提供无限可能。 篇章五&#xff1a;国内外AI大模型哪家强&#xff1f; > 设为星标公众号&#xff0c…

我校教师当选为中国计算机学会(CCF)杰出会员

近日&#xff0c;中国计算机学会&#xff08;CCF&#xff09;会员评选委员会发来贺信&#xff0c;祝贺我校信息技术学院大数据技术科研创新团队负责人陈天伟老师当选CCF杰出会员(CCF Distinguished Membership)&#xff0c;并高度评价了陈天伟的专业造诣和长期以来对CCF发展的贡…

Navicat连接数据库

一、MySQL地卸载&#xff1a; 二、Navicat连接数据库&#xff1a; 安装navicat的安装&#xff1a; 错误解决方法&#xff1a; 实验过程&#xff1a; 在本地sql数据库可以访问&#xff0c;说明数据库开启 用navicat连接&#xff1a;出现问题&#xff1a; 将mysql用户登录的加密…

欧洲欧盟药品数据库:EMA、HMA、EDQM-一键查询

在过去的一段时间里&#xff0c;我坚持不懈地每天下午都向那些精通欧洲法规注册的同事请教&#xff0c;学习EU的注册法规&#xff0c;收获颇丰。作为一个对知识充满渴望的求学者&#xff0c;今天我愿意将我学到的心得体会分享给大家&#xff0c;希望你们能够喜欢。 几个月前&a…

App推广新利器:Xinstall应用间跳转,转化效率翻倍

在移动互联网时代&#xff0c;App已成为我们生活中不可或缺的一部分。然而&#xff0c;随着App数量的不断增加&#xff0c;用户在使用过程中经常需要在多个应用之间切换&#xff0c;这不仅影响了用户体验&#xff0c;还降低了App的转化效率。今天&#xff0c;就让我们一起了解一…