vector的深入剖析与底层逻辑

前言:

上篇我们谈到vector的概念,使用,以及相关接口的具体应用,本文将对vector进行深入剖析,为读者分享其底层逻辑,讲解其核心细节。

上篇链接:

初始vector——数组的高级产物-CSDN博客

一.vector的基本结构与初始化

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

  • 实现一个空的vector,不分配任何内存。
  • 测试是否创建了容量为0的vector
  • 代码示例如下
namespace W {
    template<class T>
    class vector {
    public:
        typedef T* iterator;

        vector() : _start(nullptr), _finish(nullptr), _endOfStorage(nullptr) {}

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

    private:
        iterator _start;
        iterator _finish;
        iterator _endOfStorage;
    };
}

 测试代码示例:

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

输出:

TestEmptyVector passed

1.2 附带默认大小和值的构造函数初始化

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

代码示例如下:

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

        vector(size_t n, const T& value = T()) {
            _start = new T[n];
            _finish = _start + n;
            _endOfStorage = _finish;
            for (size_t i = 0; i < n; ++i) {
                _start[i] = value;  // 填充默认值
            }
        }

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

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

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

    private:
        iterator _start;
        iterator _finish;
        iterator _endOfStorage;
    };
}

 测试代码:

void TestInitVector() {
    W::vector<int> v(5, 10);
    assert(v.size() == 5);  // 验证大小
    assert(v.capacity() == 5);  // 验证容量
    assert(!v.empty());  // 验证非空
    for (size_t i = 0; i < 5; ++i) {
        assert(v[i] == 10);  // 验证默认值
    }
    std::cout << "TestInitVector passed" << std::endl;
}

输出:

TestInitVector passed
 

1.3 拷贝构造函数

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

代码示例如下:

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

        vector(const vector<T>& v) {
            size_t n = v.size();
            _start = new T[n];
            _finish = _start + n;
            _endOfStorage = _finish;
            for (size_t i = 0; i < n; ++i) {
                _start[i] = v._start[i];  // 复制数据
            }
        }

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

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

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

    private:
        iterator _start;
        iterator _finish;
        iterator _endOfStorage;
    };
}

 测试代码:

void TestCopyVector() {
    W::vector<int> v1(5, 10);
    W::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 << "TestCopyVector passed" << std::endl;
}

输出:

TestCopyVector passed

1.4 赋值操作符=的实现

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

 代码示例如下:

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

        vector<T>& operator=(const vector<T>& v) {
            if (this != &v) {
                delete[] _start;  // 释放旧的空间
                size_t n = v.size();
                _start = new T[n];
                _finish = _start + n;
                _endOfStorage = _finish;
                for (size_t i = 0; i < n; ++i) {
                    _start[i] = v._start[i];  // 复制数据
                }
            }
            return *this;
        }

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

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

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

    private:
        iterator _start;
        iterator _finish;
        iterator _endOfStorage;
    };
}

测试代码:

void TestAssignVector() {
    W::vector<int> v1(5, 10);
    W::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 << "TestAssignVector passed" << std::endl;
}

 输出:

TestAssignVector passed

 二. vector的内存与容积管理

2.1 reserve函数的动态扩容

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

代码示例如下:

namespace W {
    template<class T>
    class vector {
    public:
        void reserve(size_t n) {
            if (n > capacity()) {
                size_t oldSize = size();
                T* tmp = new T[n];
                for (size_t i = 0; i < oldSize; ++i) {
                    tmp[i] = _start[i];
                }
                delete[] _start;
                _start = tmp;
                _finish = _start + oldSize;
                _endOfStorage = _start + n;
            }
        }
    };
}

 测试代码:

void TestReserveVector() {
    W::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 << "TestReserveVector passed" << std::endl;
}

输出:

TestReserveVector passed

2.2 resize函数——改变大小 

  • 实现resize函数,测试增加或减少vector大小。

代码示例如下:

namespace W {
    template<class T>
    class vector {
    public:
        void resize(size_t n, const T& value = T()) {
            if (n < size()) {
                _finish = _start + n;  // 缩小大小
            } else {
                reserve(n);
                for (iterator it = _finish; it != _start + n; ++it)
			    {
                    *it = value;  // 填充新值
                }
                _finish = _start + n;
            }
        }
    };
}

 测试示例:

void TestResizeVector() {
    W::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 << "TestResizeVector passed" << std::endl;
}

 输出:

TestResizeVector passed

分析:resize函数在拓展的时候,只会改变新拓展元素的容积。 

三. vector元素的插入与删除

3.1 push_back函数——尾插

分析:

1.插入前首先要确保容积充足,若不够则需要扩容(通常为2倍)

2.注意插入的元素位于现有元素的末尾

代码示例如下:

namespace W {
    template<class T>
    class vector {
    public:
        void push_back(const T& x) {
            // 如果空间不足,扩展容量为当前容量的两倍
            if (_finish == _endOfStorage) {
                size_t newCapacity = capacity() == 0 ? 1 : capacity() * 2;
                reserve(newCapacity);
            }

            // 在末尾插入新元素
            *_finish = x;
            ++_finish;
        }

    private:
        T* _start;
        T* _finish;
        T* _endOfStorage;
    };
}

测试代码:

void TestPushBackVector() {
    W::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 << "TestPushBackVector passed" << std::endl;
}

输出:

TestPushBackVector passed

3.2 pop_back函数——尾删

分析:

1.首先确保vector内元素不为空

2.删除后记得将_finish指针前移一位,并且并不释放该处空间

代码示例如下:

namespace W {
    template<class T>
    class vector {
    public:
        void push_back(const T& x) {
            // 如果空间不足,扩展容量为当前容量的两倍
            if (_finish == _endOfStorage) {
                size_t newCapacity = capacity() == 0 ? 1 : capacity() * 2;
                reserve(newCapacity);
            }

            // 在末尾插入新元素
            *_finish = x;
            ++_finish;
        }

    private:
        T* _start;
        T* _finish;
        T* _endOfStorage;
    };
}

测试代码:

void TestPushBackVector() {
    W::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 << "TestPushBackVector passed" << std::endl;
}

输出:

TestPushBackVector passed

 3.3 insert函数——在指定位置插入数据

分析:

1.插入前首先需要确保容积充足,如果容积不足则需要扩容

2.插入成功之后,元素需要依次后移

3.完成插入后_finish指针也要后移一位

代码示例如下:

namespace W {
    template<class T>
    class vector {
    public:
        T* insert(T* pos, const T& value) {
            assert(pos >= _start && pos <= _finish);  // 确保pos是有效指针

            // 检查空间是否足够
            if (_finish == _endOfStorage) {
                size_t newCapacity = capacity() == 0 ? 1 : capacity() * 2;
                size_t offset = pos - _start;  // 记录插入位置
                reserve(newCapacity);  // 扩容
                pos = _start + offset;  // 更新插入位置
            }

            // 将插入位置之后的元素整体向后移动
            for (T* it = _finish; it > pos; --it) {
                *it = *(it - 1);
            }

            // 插入新元素
            *pos = value;
            ++_finish;
            return pos;
        }

    private:
        T* _start;
        T* _finish;
        T* _endOfStorage;
    };
}

测试代码:

void TestInsertVector() {
    W::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 << "TestInsertVector passed" << std::endl;
}

 输出:

TestInsertVector passed

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

分析:

1.删除之前需要确保元素不为空

2.删除之后元素均需左移一位

3.删除之后_finish左移一位 

代码示例如下:

namespace W {
    template<class T>
    class vector {
    public:
        T* erase(T* pos) {
            assert(pos >= _start && pos < _finish);  // 确保pos是有效指针

            // 将pos之后的元素向前移动
            for (T* it = pos; it < _finish - 1; ++it) {
                *it = *(it + 1);
            }

            --_finish;  // 更新_finish指针
            return pos;
        }

    private:
        T* _start;
        T* _finish;
        T* _endOfStorage;
    };
}

测试代码:

void TestEraseVector() {
    W::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 << "TestEraseVector passed" << std::endl;
}

 输出:

TestEraseVector passed

四. vector首尾元素的直接获取

4.1 front函数——返回第一个元素

代码示例如下:

namespace W {
    template<class T>
    class vector {
    public:
        T& front() {
            assert(!empty());  // 确保vector非空
            return *_start;  // 返回第一个元素
        }

    private:
        T* _start;
        T* _finish;
        T* _endOfStorage;
    };
}

 测试代码:

void TestFrontVector() {
    W::vector<int> v;
    v.push_back(10);
    assert(v.front() == 10);  // 验证front

    v.push_back(20);
    assert(v.front() == 10);  // 验证front不变

    std::cout << "TestFrontVector passed" << std::endl;


}

输出:

TestFrontVector passed

 4.2 back函数——返回最后一个元素

代码示例如下:

namespace W {
    template<class T>
    class vector {
    public:
        T& back() {
            assert(!empty());  // 确保vector非空
            return *(_finish - 1);  // 返回最后一个元素
        }

    private:
        T* _start;
        T* _finish;
        T* _endOfStorage;
    };
}

测试代码:

void TestBackVector() {
    W::vector<int> v;
    v.push_back(10);
    assert(v.back() == 10);  // 验证back

    v.push_back(20);
    assert(v.back() == 20);  // 验证back变化

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

输出:

TestBackVector passed

五. 迭代器的基本操作

5.1 begin函数与end函数

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

代码示例如下:

namespace W {
    template<class T>
    class vector {
    public:
        typedef T* iterator;  // 使用原生指针作为迭代器

        iterator begin() {
            return _start;
        }

        iterator end() {
            return _finish;
        }

    private:
        T* _start;
        T* _finish;
        T* _endOfStorage;
    };
}

 测试代码:

void TestIteratorVector() {
    W::vector<int> v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);

    // 使用迭代器遍历 vector
    for (W::vector<int>::iterator it = v.begin(); it != v.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

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

输出:

10 20 30 
TestIteratorVector passed

 5.2 swap函数——交换两个vector

  • swap 函数用于交换两个 vector 的内容,包括它们的起始指针、结束指针和容量指针。
  • swap 函数是常用的优化操作,特别是在实现移动语义时能大大提高效率。

代码示例如下:

namespace W {
    template<class T>
    class vector {
    public:
        void swap(vector<T>& v) {
            std::swap(_start, v._start);
            std::swap(_finish, v._finish);
            std::swap(_endOfStorage, v._endOfStorage);
        }

    private:
        T* _start;
        T* _finish;
        T* _endOfStorage;
    };
}

 测试代码:

void TestSwapVector() {
    W::vector<int> v1;
    W::vector<int> v2;

    v1.push_back(1);
    v1.push_back(2);
    v2.push_back(3);
    v2.push_back(4);
    
    v1.swap(v2);

    // 验证 v1 和 v2 交换后内容是否正确
    for (auto e : v1) {
        std::cout << e << " ";
    }
    std::cout << std::endl;

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

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

输出:

3 4 
1 2 
TestSwapVector passed

六. 赋值运算符重载——深拷贝vector (现代写法)

深拷贝之后实现与一个值与原先vector相同,但又相互独立的新vector。

其核心在于地址的不同,与拷贝构造函数同理,否则则为浅拷贝,两者间对任一一个进行增删查改也会对对方产生影响。

注意:使用 传值(pass-by-value)参数,配合 swap 函数,使代码简洁高效,且异常安全。

代码示例如下:

namespace W {
    template<class T>
    class vector {
    public:
        //这里可以服用reserve和push_back函数了
        vector(const vector<T>& v)
            : _start(nullptr), _finish(nullptr), _endOfStorage(nullptr)
        {
            reserve(v.size());  // 分配所需空间
            for (const T& elem : v) {
                push_back(elem);  // 拷贝每个元素
            }
        }

        // 赋值操作符,使用拷贝并交换技术
        vector<T>& operator=(vector<T> v) {
            swap(v);  // 调用 swap 函数交换内容
            return *this;
        }

        // swap 函数
        void swap(vector<T>& v) {
            std::swap(_start, v._start);
            std::swap(_finish, v._finish);
            std::swap(_endOfStorage, v._endOfStorage);
        }

        // 其他成员函数同之前实现...

    private:
        T* _start;
        T* _finish;
        T* _endOfStorage;
    };
}

 测试代码:

void TestCopyAndAssignVector() {
    // 测试拷贝构造函数
    W::vector<int> v1;
    v1.push_back(1);
    v1.push_back(2);
    v1.push_back(3);

    W::vector<int> v2(v1);  // 使用拷贝构造函数
    for (size_t i = 0; i < v2.size(); ++i) {
        assert(v2[i] == v1[i]);  // 验证每个元素是否相同
    }

    // 测试赋值操作符
    W::vector<int> v3;
    v3 = v1;  // 使用赋值操作符
    for (size_t i = 0; i < v3.size(); ++i) {
        assert(v3[i] == v1[i]);  // 验证每个元素是否相同
    }

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

现代写法说明:


传值参数:通过传递 vector<T> 的值作为参数,创建一个临时对象 v。调用拷贝构造函数时自动执行拷贝,然后在赋值操作中与现有对象交换内容。传值是安全的,避免了手动内存管理问题。


swap:通过交换数据成员 _start、_finish 和 _endOfStorage,避免手动内存释放,简化代码逻辑。交换后的临时对象 v 离开作用域时自动销毁,保证资源释放。

小结:本文承接上篇vector基础部分的讲解,继续对其底层逻辑和相关属性进行深入剖析。每一特

性都给出了详解解释与示例,欢迎各位佬前来支持斧正!

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CDGA|数据治理:如何让传统行业实现数据智能

在当今这个数字化时代&#xff0c;数据已成为推动各行各业转型升级的关键力量。对于传统行业而言&#xff0c;如何从海量、复杂的数据中挖掘价值&#xff0c;实现“数据智能”&#xff0c;成为了提升竞争力、优化运营效率、创新业务模式的重要途径。本文将探讨数据治理如何助力…

【文献及模型、制图分享】干旱区山水林田湖草沙冰一体化保护与系统治理——基于土地退化平衡视角

文献介绍 目标明晰、统筹兼顾、干预适度是山水林田湖草沙冰一体化保护与系统治理的客观要求。基于土地退化平衡&#xff08;LDN&#xff09;视角&#xff0c;构建涵盖双重对象、双重法则、双重原则、指标体系、价值取向的理论框架&#xff0c;并以天山北坡城市群为例&#xff…

Flume抽取数据(包含自定义拦截器和时间戳拦截器)

flume参考网址&#xff1a;Flume 1.9用户手册中文版 — 可能是目前翻译最完整的版本了https://flume.liyifeng.org/?flagfromDoc#要求&#xff1a; 使用Flume将日志抽取到hdfs上&#xff1a;通过java代码编写一个拦截器&#xff0c;将日志中不是json数据的数据过滤掉&#xf…

模拟退火算法最常见知识点详解与原理简介控制策略

章节目录 模拟退火算法简介与原理 算法的基本流程与步骤 关键参数与控制策略 模拟退火算法的应用领域 如何学习模拟退火算法 资源简介与总结 一、模拟退火算法简介与原理 重点详细内容知识点总结 1. 模拟退火算法简介 模拟退火算法&#xff08;Simulated Annealing, SA&#x…

blender分离含有多个动作的模型,并导出含有材质的fbx模型

问题背景 笔者是模型小白&#xff0c;需要将网络上下载的fbx模型中的动作&#xff0c;分离成单独的动作模型&#xff0c;经过3天摸爬滚打&#xff0c;先后使用了blender&#xff0c;3d max&#xff0c;unity&#xff0c;最终用blender完成&#xff0c;期间参考了众多网络上大佬…

Spring Boot框架下大创项目流程自动化

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理大创管理系统的相关信息成为必然。开发合适…

DETR[端到端目标检测](论文复现)

DETR[端到端目标检测](论文复现) 本文所涉及所有资源均在传知代码平台可获取 文章目录 DETR[端到端目标检测](论文复现)概述模型主体框架演示效果核心逻辑使用方式部署方式数据准备概述 在目标检测需要许多手工设计的组件,例如非极大值抑制(NMS),基于人工经验生成的先验…

【Trulens框架】用TruLens 自动化 RAG 应用项目评估测试

前言&#xff1a; 什么是Trulens TruLens是面向神经网络应用的质量评估工具&#xff0c;它可以帮助你使用反馈函数来客观地评估你的基于LLM&#xff08;语言模型&#xff09;的应用的质量和效果。反馈函数可以帮助你以编程的方式评估输入、输出和中间结果的质量&#xff0c;从而…

Gin框架操作指南10:服务器与高级功能

官方文档地址&#xff08;中文&#xff09;&#xff1a;https://gin-gonic.com/zh-cn/docs/ 注&#xff1a;本教程采用工作区机制&#xff0c;所以一个项目下载了Gin框架&#xff0c;其余项目就无需重复下载&#xff0c;想了解的读者可阅读第一节&#xff1a;Gin操作指南&#…

SICK系列激光雷达单点测距仪DT80-311111+SIG200配置和通信

文章目录 一、硬件连接与SOPAS连接测距仪二、从SOPAS读取数据三、通过JSON获取数据1. 使用Postman测试接口2. 通过代码实现 一、硬件连接与SOPAS连接测距仪 首先硬件设备连接如下&#xff1a; 电源厂家应该是不提供&#xff0c;需要自行解决。 安装完成后需要使用sick的SOPAS…

增量知识 (Incremental Knowledge, IK)

在语义通信系统中&#xff0c;增量知识&#xff08;IK, Incremental Knowledge&#xff09;是一种增强数据传输效率和可靠性的技术&#xff0c;特别是用于混合自动重传请求&#xff08;HARQ, Hybrid Automatic Repeat reQuest&#xff09;机制时。它的核心思想是在传输失败后&a…

图像中的融合

图像显示函数 def img_show(name, img):"""显示图片:param name: 窗口名字:param img: 图片对象:return: None"""cv2.imshow(name, img)cv2.waitKey(0)cv2.destroyAllWindows()图像读取与处理 读取图片 cloud cv2.imread(bg.jpg) fish cv2.…

【uni-app】HBuilderX安装uni-ui组件

目录 1、官网找到入口 2、登录帐号 3、打开HuilderX 4、选择要应用的项目 5、查看是否安装完成 6、按需安装 7、安装完毕要重启 8、应用 前言&#xff1a;uniapp项目使用uni-ui组件方式很多&#xff0c;有npm安装等&#xff0c;或直接创建uni-ui项目&#xff0c;使用un…

threejs-光线投射实现3d场景交互事件

一、介绍 1.属性 // 创建射线 const raycaster new three.Raycaster() // 创建鼠标向量(保存鼠标点击位置) const mouse new three.Vector2() // 创建点击事件 window.addEventListener(click,(event)>{// 获取鼠标点击位置mouse.x (event.clientX / window.innerWidt…

HAL+M4学习记录_7

一、TIM 记录学习HAL配置TIM定时器 1.1 简介 TIM&#xff08;timer&#xff09;定时器&#xff0c;16位或32位&#xff08;TIM2和TIM5&#xff09;计数器、预分频器&#xff08;16位&#xff09;、自动重装寄存器的时基单元&#xff1b;可对输入时钟进行计数&#xff0c;在计数…

PyQt 入门教程(3)基础知识 | 3.1、使用QtDesigner创建.ui文件

文章目录 一、使用QtDesigner创建.ui文件1、创建.ui文件2、生成.py文件3、使用新生成的.py文件4、编辑新生成的.py文件 一、使用QtDesigner创建.ui文件 1、创建.ui文件 打开PyCharm&#xff0c;使用自定义外部工具QtDesigner创建mydialog.ui文件&#xff0c;如下&#xff1a; …

finalshell连接navicat数据库

一、安装mysql数据库 这个安装在另外一篇里 超详细的finalshell安装数据库以及数据库的基本操作-CSDN博客https://blog.csdn.net/cfjbcg/article/details/142990671 二、连接 说明root这个用户连接&#xff0c;是有权限的限制的----》修改权限 use mysql pdate user set hos…

测试教程分享

前几年在腾讯课堂上发布了不少课程&#xff0c;后来腾讯课堂改革&#xff0c;要收会员费&#xff0c;课程还要抽提程&#xff0c;这么下来就相当于白干了。就放弃了在上面发课程&#xff0c;再后来腾讯课堂就关闭了&#xff0c;以前发布的视频就没有地方发了&#xff0c;于是我…

Golang | Leetcode Golang题解之第485题最大连续1的个数

题目&#xff1a; 题解&#xff1a; func findMaxConsecutiveOnes(nums []int) (maxCnt int) {cnt : 0for _, v : range nums {if v 1 {cnt} else {maxCnt max(maxCnt, cnt)cnt 0}}maxCnt max(maxCnt, cnt)return }func max(a, b int) int {if a > b {return a}return …

QT--Qlabel学习、获取文本和设置文本、文本对齐方式、文本换行、显示图片

QLabel 是 Qt 中的标签类&#xff0c;通常用于显示提示性的文本&#xff0c;也可以显示图像 对齐方式 用于设置标签中的内容在水平和垂直两个方向上的对齐方式&#xff0c;比如左对齐、右对齐、上对齐、下对齐、水平居中、垂直居中等。 // 获取和设置文本的对齐方式 Qt::Ali…