【039】掌握Vector容器:C++中最强大的动态数组

news2024/12/27 13:04:38

掌握Vector容器:C++中最强大的动态数组

  • 引言
  • 一、vector容器概述
  • 二、vector的数据结构
  • 三、vector常用的API操作
    • 3.1、vector构造函数
    • 3.2、vector常用的赋值操作
    • 3.3、vector的大小操作
    • 3.4、vector存取数据操作
    • 3.5、vector插入和删除操作
  • 四、vector的未雨绸缪机制
  • 五、巧用swap()收缩空间
  • 六、vector的运用实例
    • 6.1、vector的嵌套
    • 6.2、使用STL算法对vector排序
    • 6.3、vector存放自定义的数据
  • 总结

引言


💡 作者简介:一个热爱分享高性能服务器后台开发知识的博主,目标是通过理论与代码实践的结合,让世界上看似难以掌握的技术变得易于理解与掌握。技能涵盖了多个领域,包括C/C++、Linux、Nginx、MySQL、Redis、fastdfs、kafka、Docker、TCP/IP、协程、DPDK等。
👉
🎖️ CSDN实力新星、CSDN博客专家
👉
🔔 专栏介绍:从零到c++精通的学习之路。内容包括C++基础编程、中级编程、高级编程;掌握各个知识点。
👉
🔔 专栏地址:C++从零开始到精通
👉
🔔 博客主页:https://blog.csdn.net/Long_xu


🔔 上一篇:【038】解码C++ STL:探索string容器的无限可能与鲜为人知的技巧

一、vector容器概述

vector的数据安排以及操作方式与array非常相似,两者的唯一差别在于空间的运用的灵活性。Array是静态空间,一旦配置了就不能改变,要换大一点或者小一点的空间,是被允许的,但是一切琐碎得由自己来,首先配置一块新的空间,然后将旧空间的数据搬往新空间,再释放原来的空间。

vector是动态空间,随着元素的加入,它的内部机制会自动扩充空间以容纳新元素。因此 vector的运用对于内存的合理利用与运用的灵活性有很大的帮助,再也不必害怕空间不足而一开始就要求一个大块头的array了。

vector的实现技术,关键在于其对大小的控制以及重新配置时的数据移动效率,一旦vector l旧空间满了,如果客户每新增一个元素,vector内部只是扩充一个元素的空间,实为不智,因为所谓的扩充空间(不论多大),一如刚所说,是"配置新空间-·数据移动-释放旧空间"的大工程时间成本很高,应该加入某种未雨绸缪的空间配置策略。
在这里插入图片描述

  • v.begin():获取容器的起始迭代器(指向第一个元素)。
  • v.end():获取容器的结束迭代器(指向最后一个元素的下一个元素位置)。

特点和优势:

  1. 动态大小:vector可以在运行时根据需要自动调整大小,无需手动管理内存。它可以根据元素的插入或删除自动扩展或收缩。

  2. 随机访问:通过索引可以快速随机访问vector中的元素。这使得vector非常适用于需要频繁访问、查找和修改元素的场景。

  3. 连续内存存储:vector的元素在内存中以连续的方式存储,这样可以提高缓存命中率,加快元素的访问速度。

  4. 元素的添加和删除:vector支持在尾部添加元素(push_back)和删除尾部元素(pop_back),以及在指定位置插入元素和移除元素。相对于数组,这些操作更加灵活方便。

  5. 内存管理:vector会自动管理内存,当元素数量超过当前容量时,会重新申请一块更大的内存,并将元素从旧内存复制到新内存中。这减少了我们手动进行内存管理的工作量。

  6. 可以存储任意类型:vector可以存储任何C++数据类型,包括基本类型、自定义结构体和类对象等。

使用vector时,需要包含头文件 #include <vector>

二、vector的数据结构

Vector 所采用的数据结构非常简单,线性连续空间,它以两个迭代器Myfirst和Mylast分别指向配置得来的连续空间中目前已被使用的范围,并以迭代器_Myend指向整块连续内存空间的尾端。为了降低空间配置时的速度成本,vector实际配置的大小可能比客户端需求大一些,以备将来可能的扩充,这边是容量的概念。换句话说,一个vector的容量永远大于或等于其大小,一旦容量等于大小,便是满载,下次再有新增元素,整个vector容器就得另觅居所。

注意:所谓动态增加大小,并不是在原空间之后续接新空间(因为无法保证原空间之后尚有可配置的空间),而是一块更大的内存空间,然后将原数据拷贝新空间,并释放原空间。因此,对vector的任何操作,一旦引起空间的重新配置,指向原vector的所有迭代器就都失效了。这是程序员容易犯的一个错误,务必小心。

C++中的vector容器通常使用动态数组来实现。其数据结构可简单描述为:

  1. 指向存储数据的动态数组的指针:vector在内部使用一个指针来引用动态分配的连续内存块,该内存块用于存储元素。

  2. 大小和容量:vector包含两个重要的成员变量,即元素数量(Size)和容量(Capacity)。元素数量表示当前vector中实际存储的元素个数,而容量表示vector当前分配的内存空间能容纳的元素个数。

  3. 元素访问:通过索引访问vector中的元素是常数时间复杂度(O(1)),因为元素在内存中是连续存储的。

  4. 动态扩展:当vector中的元素数量超过当前容量时,vector会重新申请更大的内存,并将旧内存中的元素复制到新内存中。扩展策略可以保证高效的插入和删除操作。

  5. 迭代器支持:vector提供正向迭代器,使得可以方便地遍历容器中的元素。

C++的vector是通过动态分配的连续内存块来存储元素,通过索引访问和修改元素,并根据需要自动调整内存大小以容纳更多元素。这种设计使得vector成为一个灵活、高效的动态数组容器,适用于各种常见的数据管理和操作场景。

三、vector常用的API操作

3.1、vector构造函数

C++的vector容器提供了多个构造函数来创建和初始化vector对象。以下是一些常用的vector构造函数原型:

  1. 默认构造函数:创建一个空的vector对象。

    vector();
    
  2. 带初始大小和值的构造函数:

    vector(size_type count, const T& value = T());
    

    创建一个包含count个元素的vector对象,每个元素都被初始化为value的副本。

  3. 带初始范围的构造函数:

    template <class InputIterator>
    vector(InputIterator first, InputIterator last);
    

    创建一个包含范围在[first, last)内的元素的vector对象。可以使用迭代器、指针或者数组来指定范围。

  4. 拷贝构造函数:

    vector(const vector& other);
    

    根据另一个vector对象other创建一个新的vector对象,包含与other相同的元素。

  5. 移动构造函数:

    vector(vector&& other);
    

    根据另一个可移动的vector对象other创建一个新的vector对象, other中的元素会被移动到新的vector对象中,原vector对象将处于有效但未指定状态。

  6. 初始化列表构造函数:

    vector(std::initializer_list<T> init);
    

    使用初始化列表初始化一个vector对象,列表中的元素被复制到vector中。

3.2、vector常用的赋值操作

  1. 使用等号进行赋值:

    vector<T>& operator=(const vector<T>& other);
    

    示例:

    vector<int> v1;
    vector<int> v2 = {1, 2, 3};
    
    v1 = v2; // 将v2中的元素赋值给v1
    
    // 输出v1的内容
    for (int num : v1) {
        cout << num << " ";
    }
    // 输出结果: 1 2 3
    
  2. 使用assign()函数进行赋值:

    void assign(InputIt first, InputIt last);
    void assign(size_type count, const T& value);
    

    示例1:

    vector<int> v1;
    vector<int> v2 = {4, 5, 6};
    
    v1.assign(v2.begin(), v2.end()); // 将v2中指定范围内的元素赋值给v1
    
    // 输出v1的内容
    for (int num : v1) {
        cout << num << " ";
    }
    // 输出结果: 4 5 6
    

    示例2:

    vector<int> v1;
    
    v1.assign(3, 100); // 将v1中的元素数量设置为3,并将每个元素的值设置为100
    
    // 输出v1的内容
    for (int num : v1) {
        cout << num << " ";
    }
    // 输出结果: 100 100 100
    
  3. 使用拷贝构造函数进行赋值:

    vector(const vector& other);
    

    示例:

    vector<int> v2 = {7, 8, 9};
    vector<int> v1(v2); // 创建一个新的vector v1,并将v2中的元素拷贝给v1
    
    // 输出v1的内容
    for (int num : v1) {
        cout << num << " ";
    }
    // 输出结果: 7 8 9
    
  4. 使用初始化列表进行赋值:

    vector(std::initializer_list<T> init);
    

    示例:

    vector<int> v1 = {10, 11, 12}; // 使用初始化列表赋值给v1
    
    // 输出v1的内容
    for (int num : v1) {
        cout << num << " ";
    }
    // 输出结果: 10 11 12
    

其中,T代表vector中存储的元素类型。具体说明如下:

  • 等号赋值操作符(=):将另一个vector的内容赋值给当前的vector。
  • assign()函数:接受输入迭代器范围或元素数量与值,并用其进行赋值。
  • 拷贝构造函数:使用另一个vector创建一个新的vector,并将其元素拷贝到新的vector中。
  • 初始化列表构造函数:使用初始化列表创建一个新的vector,并将列表中的元素赋值给它。

3.3、vector的大小操作

在C++中,vector提供了以下几个与大小相关的函数:

  1. size()函数:

    size_type size() const;
    

    示例:

    vector<int> v = {1, 2, 3, 4, 5};
    cout << "Size of v: " << v.size() << endl;
    // 输出:Size of v: 5
    

    size()函数返回当前vector中元素的数量。

  2. empty()函数:

    bool empty() const;
    

    示例:

    vector<int> v = {1, 2, 3};
    cout << (v.empty() ? "Vector is empty" : "Vector is not empty") << endl;
    // 输出:Vector is not empty
    

    empty()函数用于检查当前vector是否为空。如果vector为空,则返回true;否则返回false。

  3. resize()函数:

    void resize(size_type count);
    void resize(size_type count, const T& value);
    

    示例1:

    vector<int> v = {1, 2, 3};
    v.resize(5);  // 调整vector的大小为5
    
    cout << "Size of v after resize: " << v.size() << endl;
    // 输出:Size of v after resize: 5
    
    cout << "New elements in v:";
    for (int num : v) {
        cout << " " << num;
    }
    // 输出:New elements in v: 1 2 3 0 0
    

    示例2:

    vector<int> v = {1, 2, 3};
    v.resize(5, 100); // 调整vector的大小为5,并将新增元素的值设为100
    
    cout << "Size of v after resize: " << v.size() << endl;
    // 输出:Size of v after resize: 5
    
    cout << "New elements in v:";
    for (int num : v) {
        cout << " " << num;
    }
    // 输出:New elements in v: 1 2 3 100 100
    

    resize()函数用于调整vector的大小。第一个版本调整vector的大小为指定的count,并在新增的位置上默认填充零值。第二个版本在新增的位置上以特定的value填充。

  4. capacity()函数的原型:

    size_type capacity() const;
    

    capacity()函数返回vector当前所分配的存储空间的容量(即可以容纳的元素数量),而不是实际存储的元素数量。一般情况下,容量会大于或等于size()函数返回的大小。

  5. reserve()函数的原型:

    void reserve(size_type new_capacity);
    

    reserve()函数用于修改vector的容量,确保存储空间至少能容纳指定的元素数量new_capacity。如果new_capacity小于当前容量,则函数调用没有任何效果。如果new_capacity大于当前容量,则会重新分配足够的存储空间以适应新的容量。

下面是使用示例:

#include <iostream>
#include <vector>

int main() {
    std::vector<int> nums;

    std::cout << "Initial size: " << nums.size() << std::endl;       // 输出:Initial size: 0
    std::cout << "Initial capacity: " << nums.capacity() << std::endl; // 输出:Initial capacity: 0

    nums.reserve(10); // 修改容量为10,预留足够的空间

    std::cout << "After reserve(10) - capacity: " << nums.capacity() << std::endl; // 输出:After reserve(10) - capacity: 10

    nums.push_back(1);
    nums.push_back(2);
    nums.push_back(3);

    std::cout << "After push_back - size: " << nums.size() << std::endl;       // 输出:After push_back - size: 3
    std::cout << "After push_back - capacity: " << nums.capacity() << std::endl; // 输出:After push_back - capacity: 10

    nums.shrink_to_fit(); // 收缩存储空间以适应实际大小

    std::cout << "After shrink_to_fit - capacity: " << nums.capacity() << std::endl; // 输出:After shrink_to_fit - capacity: 3

    return 0;
}

在示例中,首先创建了一个空的vector,初始大小和容量都为0。然后使用reserve()函数将容量修改为10,预留足够的空间。接下来,使用push_back()函数向vector中添加元素,此时size()逐渐增加,但容量仍保持不变。最后,使用shrink_to_fit()函数将容量收缩到与实际大小相匹配。

3.4、vector存取数据操作

在C++中,vector提供了几种数据存取操作函数,可以用来访问和修改容器中的元素。

  1. at()函数的原型:

    reference at(size_type pos);
    const_reference at(size_type pos) const;
    

    at()函数返回指定位置pos处的元素的引用。如果pos超出了有效范围(即大于等于size()),则抛出std::out_of_range异常。

    示例:

    #include <iostream>
    #include <vector>
    
    int main() {
        std::vector<int> nums = {1, 2, 3, 4, 5};
    
        for (size_t i = 0; i < nums.size(); ++i) {
            std::cout << "Element at position " << i << ": " << nums.at(i) << std::endl;
        }
    
        return 0;
    }
    

    输出:

    Element at position 0: 1
    Element at position 1: 2
    Element at position 2: 3
    Element at position 3: 4
    Element at position 4: 5
    
  2. operator[]函数的原型:

    reference operator[](size_type pos);
    const_reference operator[](size_type pos) const;
    

    operator[]函数返回指定位置pos处的元素的引用。与at()函数不同的是,若pos超出有效范围,则行为是未定义的。也就是说at越界时会抛出异常,二[]越界不会抛出异常。

    示例:

    #include <iostream>
    #include <vector>
    
    int main() {
        std::vector<int> nums = {1, 2, 3, 4, 5};
    
        for (size_t i = 0; i < nums.size(); ++i) {
            std::cout << "Element at position " << i << ": " << nums[i] << std::endl;
        }
    
        return 0;
    }
    

    输出:

    Element at position 0: 1
    Element at position 1: 2
    Element at position 2: 3
    Element at position 3: 4
    Element at position 4: 5
    
  3. front()back()函数的原型:

    reference front();
    const_reference front() const;
    
    reference back();
    const_reference back() const;
    

    front()函数返回容器中第一个元素的引用,而back()函数返回容器中最后一个元素的引用。

    示例:

    #include <iostream>
    #include <vector>
    
    int main() {
        std::vector<int> nums = {1, 2, 3, 4, 5};
    
        std::cout << "First element: " << nums.front() << std::endl;
        std::cout << "Last element: " << nums.back() << std::endl;
    
        return 0;
    }
    

    输出:

    First element: 1
    Last element: 5
    
  4. data()函数的原型:

    T* data();
    const T* data() const;
    

    data()函数返回指向容器存储数据的指针。这个指针允许对容器中的元素进行修改。

    示例:

    #include <iostream>
    #include <vector>
    
    int main() {
        std::vector<int> nums = {1, 2, 3, 4, 5};
    
        int* ptr = nums.data();
    
        for (size_t i = 0; i < nums.size(); ++i) {
            std::cout << "Element at position " << i << ": " << *(ptr + i) << std::endl;
        }
    
        return 0;
    }
    

    输出:

    Element at position 0: 1
    Element at position 1: 2
    Element at position 2: 3
    

3.5、vector插入和删除操作

在C++中,vector提供了多个用于插入和删除元素的操作函数。下面是其中一些常用函数的原型和使用示例:

  1. 插入操作:

    • push_back():将元素添加到vector的末尾。

      void push_back(const T& value);
      

      示例:

      std::vector<int> nums;
      nums.push_back(1);
      nums.push_back(2);
      
    • insert():在指定位置插入一个或多个元素。

      iterator insert(iterator position, const T& value);                             // 在指定位置插入单个元素
      void insert(iterator position, size_type n, const T& value);                     // 在指定位置插入多个相同元素
      template <class InputIterator>
      void insert(iterator position, InputIterator first, InputIterator last);         // 在指定位置插入一个范围内的元素
      

      示例:

      std::vector<int> nums = {1, 2, 3};
      auto it = nums.begin() + 1;  // 在第二个位置插入元素
      nums.insert(it, 4);          // 插入单个元素
      nums.insert(it, 2, 5);       // 插入多个相同元素
      
  2. 删除操作:

    • pop_back():删除vector末尾的元素。

      void pop_back();
      

      示例:

      std::vector<int> nums = {1, 2, 3};
      nums.pop_back();  // 删除末尾元素,vector变为 {1, 2}
      
    • erase():删除指定位置或范围内的元素。

      iterator erase(iterator position);                          // 删除单个元素
      iterator erase(iterator first, iterator last);              // 删除一个范围内的元素
      

      示例:

      std::vector<int> nums = {1, 2, 3, 4, 5};
      auto it = nums.begin() + 2;    // 删除第三个元素
      nums.erase(it);
      nums.erase(nums.begin(), nums.begin() + 2);  // 删除前两个元素,vector变为 {3, 4, 5}
      
    • clear():删除容器中所有的元素。仅清空了大小,容量还是存在的。

请注意,在使用这些函数时,需要确保迭代器的有效性或正确计算插入和删除位置。

四、vector的未雨绸缪机制

C++的vector是一种动态数组容器,它在内存管理上具有未雨绸缪的机制,以避免频繁的内存重新分配和数据复制操作。

当向vector添加元素时,如果当前元素数量超过了当前分配的内存空间(即容量),vector会执行以下步骤来进行未雨绸缪:

  1. 分配更大的内存空间:vector会根据需要自动申请一块更大的内存空间,通常是当前容量的两倍。这样可以确保将来有足够的空间来存储更多的元素。

  2. 复制元素:vector会将当前内存中的元素复制到新的内存空间中。这确保了数据在内存中的连续性,以便于支持随机访问和迭代器操作。

  3. 释放旧内存:vector会释放之前分配的较小内存空间,以避免内存泄漏。

通过执行未雨绸缪机制,vector能够有效地管理内存,避免反复的内存分配和数据复制,从而提高性能和效率。然而,如果预先知道vector可能存储的元素数量,可以使用reserve()函数手动设置容量,以避免不必要的内存重新分配操作。

示例:

int main()
{
	cout << "#########################" << endl;
	vector<int> arr;
	int i = 0;
	int count = 0;// 统计开辟空间次数
	vector<int>::iterator it;// 指向起始迭代器
	
	
	cout << "空间:" << arr.capacity() << ",大小:" << arr.size() << endl;

	for (i = 0; i < 1000; i++)
	{
		arr.push_back(i);
		
		if (arr.begin()!=it)
		{
			
			count++;
			cout << "第"<<count<<"次分配空间:" << arr.capacity() << endl;

			it = arr.begin();
		}
	}
	return 0;
}

五、巧用swap()收缩空间

resize()只能修改大小,无法改变容量;如果要收缩容量,需要巧用swap()函数。
假设有1000个元素的容量需要收缩空间:
在这里插入图片描述
交换空间:
在这里插入图片描述
在C++中,vector容器的大小会根据元素的增加和删除而动态改变。当删除元素后,vector实际占用的内存空间可能大于容器当前的大小。如果想要减少内存的占用,可以使用 swap() 函数来进行收缩空间的操作。

swap() 函数通过交换容器内部的数据来实现收缩空间的效果。具体步骤如下:

  1. 使用 vector 容器的成员函数 resize() 将容器的大小调整为实际需要的大小。
  2. 创建一个临时的空 vector 容器。
  3. 使用 swap() 函数将空 vector 和原 vector 进行交换。
  4. 临时 vector 自动销毁,释放其占用的内存空间。

以下是收缩空间的示例代码:

#include <iostream>
#include <vector>

int main() {
    std::vector<int> nums = {1, 2, 3, 4, 5};

    std::cout << "Before shrink: Size = " << nums.size() << " Capacity = " << nums.capacity() << std::endl;

    nums.resize(nums.size());   // 调整容器大小为实际大小
    std::vector<int>(nums).swap(nums);   // 使用swap()进行空间收缩

    std::cout << "After shrink: Size = " << nums.size() << " Capacity = " << nums.capacity() << std::endl;

    return 0;
}

运行以上代码,输出结果为:

Before shrink: Size = 5 Capacity = 8
After shrink: Size = 5 Capacity = 5

可以看到,在执行了 swap() 操作之后,vector 容器的实际占用空间被收缩,与容器内元素数量相匹配。这样可以有效减少不必要的内存占用。

六、vector的运用实例

6.1、vector的嵌套

在C++中,vector容器支持嵌套,也就是说可以创建存储其他容器的容器。这种嵌套使用可以帮助我们组织和管理多维数据结构,提供更灵活的数据存储方式。

#include <iostream>
#include <vector>

int main() {
    // 创建一个二维vector
    std::vector<std::vector<int>> matrix;

    // 添加第一行数据
    std::vector<int> row1 = {1, 2, 3};
    matrix.push_back(row1);

    // 添加第二行数据
    std::vector<int> row2 = {4, 5, 6};
    matrix.push_back(row2);

    // 访问和修改元素
    std::cout << "Element at matrix[0][1]: " << matrix[0][1] << std::endl;
    matrix[1][2] = 7;

    // 遍历打印二维vector
    for (const auto& row : matrix) {
        for (const auto& element : row) {
            std::cout << element << " ";
        }
        std::cout << std::endl;
    }

    return 0;
}

运行以上代码,输出结果为:

Element at matrix[0][1]: 2
1 2 3 
4 5 7 

可以看到,创建了一个二维的vector容器 matrix,并通过向其中添加一维的vector作为行数据来构建二维结构。

通过使用下标操作符 [],我们可以访问和修改二维vector中的元素。例如,matrix[0][1]表示获取第一行第二个元素的值,并将其输出到控制台。

我们也可以使用嵌套的循环遍历打印整个二维vector的内容。

需要注意的是,在嵌套的vector容器中,每一行的长度可以不同,即每个子vector的大小可以不一致。这是vector相比于内置数组的一个优势之一。

6.2、使用STL算法对vector排序

使用STL算法对vector进行排序非常简单,可以使用std::sort函数。std::sort函数是C++标准模板库中的一个排序算法,它对容器中的元素进行升序排序。

示例:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> numbers = {5, 2, 8, 6, 1, 3, 7, 4};

    // 对vector进行排序
    std::sort(numbers.begin(), numbers.end());

    // 打印排序后的vector
    for (const auto& num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    return 0;
}

运行以上代码,输出结果为:

1 2 3 4 5 6 7 8 

在上述示例中,我们创建了一个名为numbersvector,其中包含一些整数。然后,使用std::sort函数对numbers进行排序,将其元素按升序排列。

最后,使用循环遍历打印排序后的vector中的元素。

需要注意的是,std::sort函数要求可以通过迭代器访问容器的数据,因此使用numbers.begin()numbers.end()作为参数传递给std::sort,表示需要对整个vector范围内的元素进行排序。

通过使用STL算法,可以方便地对vector进行排序,并且也可以使用自定义的比较函数或lambda表达式来实现不同的排序需求。

6.3、vector存放自定义的数据

在C++中,vector可以存放自定义的类对象。只需确保自定义类满足以下要求:

  1. 类必须有默认构造函数和复制构造函数(可以是用户定义的或者编译器生成的)。
  2. 类可以被复制(满足复制语义)。

使用自定义类型,当排序时需要指定比较规则。

示例:

#include <iostream>
#include <vector>
#include <algorithm>

// 自定义类
class MyClass {
public:
    int data;

    MyClass(int value) : data(value) {}
};

bool comapreObj(MyClass &ob1,MyClass &ob2)
{
	return ob1.data<ob2.data;
}

int main() {
    // 创建一个存放MyClass对象的vector
    std::vector<MyClass> myVector;

    // 添加对象到vector
    myVector.push_back(MyClass(1));
    myVector.push_back(MyClass(2));
    myVector.push_back(MyClass(6));
    myVector.push_back(MyClass(3));

    // 遍历对象并打印数据
    for (const auto& obj : myVector) {
        std::cout << obj.data << " ";
    }
	std::sort(myVector.begin(),myVector.end(),comapreObj);
	 // 遍历对象并打印数据
    for (const auto& obj : myVector) {
        std::cout << obj.data << " ";
    }

    return 0;
}

运行以上代码,输出结果为:

1 2 6 3
1 2 3 6

需要注意的是,当将自定义类对象存放到 vector 中时,会调用复制构造函数来创建新的对象,并将其添加到容器中。如果类没有复制构造函数或者编译器生成的复制构造函数无法满足需求,可能需要手动定义复制构造函数来确保对象正确地进行复制和存储。

总结

Vector是C++标准库提供的一个非常强大的动态数组容器,可以灵活地管理元素,并且具有许多重要的特性。

  1. Vector是一个动态数组容器,可以自动调整大小以适应存储元素的需求。它在内部使用连续的内存来存储元素。

  2. Vector允许在尾部高效地添加和删除元素,通过使用push_backpop_back操作。

  3. Vector支持随机访问元素,可像普通数组一样使用索引访问数据。使用[]运算符或at()函数可以获得指定位置的元素。

  4. Vector提供了很多有用的成员函数和算法,如size()获取元素个数、empty()检查是否为空、clear()清空容器等。

  5. 使用resize()函数可以改变容器的大小,使其包含指定数量的元素。

  6. Vector是一个模板类,可以存储任意类型的对象,包括内置类型和自定义类。

  7. Vector会自动处理内存分配和释放,不需要手动管理内存。

  8. Vector的迭代器用于遍历容器中的元素,可以进行正向和反向遍历。

  9. Vector可以通过拷贝构造函数和赋值运算符进行复制和赋值,使得可以方便地创建副本或对容器进行复制。

  10. Vector的缺点是:在尾部添加或删除元素时效率较高,但在中间或开头位置插入或删除元素会导致数据的移动,影响性能。

在这里插入图片描述

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

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

相关文章

数据库应用:CentOS 7离线安装PostgreSQL

目录 一、理论 1.PostgreSQL 2.PostgreSQL离线安装 3.PostgreSQL初始化 4.PostgreSQL登录操作 二、实验 1.CentOS 7离线安装PostgreSQL 2.登录PostgreSQL 3.Navicat连接PostgreSQL 三、总结 一、理论 1.PostgreSQL &#xff08;1&#xff09;简介 PostgreSQL 是一个…

vue3 -- mitt 插件使用

介绍 mitt插件是Vue3中的一种第三方总线插件,它可以用于在组件之间进行通信。相比于Vue实例上的EventBus,mitt.js足够小,仅有200bytes,支持全部事件的监听和批量移除,它还不依赖Vue实例,所以可以跨框架使用,React或者Vue,甚至jQuery项目都能使用同一套库 . 使用 1:下载插…

Interactive Image Segmentation

Focused and Collaborative Feedback Integration for Interactive Image Segmentation CVPR 2023 清华 Interactive image segmentation aims at obtaining a segmentation mask for an image using simple user annotations. During each round of interaction, the segment…

windows打开此类文件前总是询问怎么解决

打开此类文件前总是询问怎么解决这个一直提示的问题呢&#xff1f; 下面来教大家一个方法杜绝再提示&#xff1a; 开始 --> 运行 --> gpedit.msc (组策略) --> 用户配置 --> 管理模板 --> windows组件 --> 附件管理器 --> 右击 "中等危险文件类型的包…

再学JavaScript

九、常见的运算符 两个等号只判断值&#xff0c;三个等号判断值和类型是否相等 逻辑运算符 注意&&和& ||和| 短路 赋值运算符 自加自减运算符 三目运算符 移位运算符 十、JavaScript的数据类型转换 假如用默认值10&#xff0c;控制台结果就是1035&#xff08…

学生管理系统--java+mysql

学生管理系统 简介 练习&#xff1a;完成学生信息的增删查改&#xff08;根据id&#xff09;&#xff0c;项目进行了三层架构进行创建。 pojo层&#xff0c;dao层&#xff0c;service层&#xff0c;utils层&#xff0c;程序入口&#xff1b; 1.pojo层 实体层 数据库在项目…

基于linux下的高并发服务器开发(第一章)- dup,dup2函数

int dup(int oldfd);复制文件描述符 /*#include <unistd.h>int dup(int oldfd);作用&#xff1a;复制一个新的文件描述符fd3, int fd1 dup(fd),fd指向的是a.txt, fd1也是指向a.txt从空闲的文件描述符表中找一个最小的&#xff0c;作为新的拷贝的文件描述符*/#include &…

80C51定时/计数器的应用之实现PWM(脉冲宽度调制)

知识来源于链接&#xff1a;https://www.bilibili.com/video/BV1eT4y1J7wB/?spm_id_from333.880.my_history.page.click&vd_sourceb91967c499b23106586d7aa35af46413 这种模拟实现 PWM 波的应用只能应用于对波形精度和频率要求不高的情况下。 一、程序思路分析 这里想要…

Redis缓存雪崩、穿透、击穿原因分析和解决方案,附Redis管道使用技巧

先给大家附上其他几篇文章&#xff0c;感兴趣的自行开车导航 Redis过期策略和持久化机制全面揭秘&#xff0c;教你如何合理配置 【深入浅出Redis 一】从版本特性到数据类型到线程模型&#xff0c;带你了解Redis的核心特性和应用场景&#xff01; 一次redis OOM问题分析解决&…

PyTorch深度学习——Anaconda和PyTorch安装

一、Anaconda安装 前言 安装anaconda后主要有一下3点好处&#xff1a; 1.包含环境管理器conda。 2.大量安装基于python的工具包。 3.可以创建使用和管理不同的python版本。 附上百度百科的解释&#xff1a; 下载步骤&#xff1a; 1.官网下载anaconda 2.双击之后安装即可 …

【Linux】进程间通信——管道与共享内存

文章目录 前言 1、三个问题1-1、什么是通信&#xff1f;1-2、为什么要有通信1-3、怎么进行通信&#xff1f;1-4、进程间通信分类 2、管道2-1、匿名管道2-1-1、理解通信本质问题2-1-2、进一步理解管道2-1-3、代码实现pipe函数 2-1-4、读写特征2-1-5、管道的特点&#xff08;重点…

MQTT springboot + idea

参考链接&#xff1a;&#xff08;第一个是理论 第二个是代码 我是直接cv的 我就不贴代码了&#xff09; MQTT协议基本流程、原理_mqtt协议工作原理_Nimrod__的博客-CSDN博客 SpringBoot整合MQTT_springboot mqtt_N_P_E的博客-CSDN博客 EMQX 入门教程③——默认端口、端口策…

10.Java 基本数据类型与包装类之间的转换

Java 的包装类便是一种特殊的引用数据类型&#xff0c;因为其是与基本数据类型一一对应的 1.装箱和拆箱 装箱指的是将基本数据类型转为包装类&#xff1b;拆箱指的是将包装类转为基本数据类型 1.1 int 与 Integer 之间的转换 int → Integer int i 13; Integer integer I…

基于JSP+servlet+JDBC开发的人物管理系统

文章目录 技术说明【效果图】源码 技术说明 后端&#xff1a;JspServletJDBC 前端&#xff1a;BootStrap技术 数据库&#xff1a;Mysql 其他&#xff1a;ckeditor富文本编辑器、FileUpload组件上传图片、MD5加密技术 功能&#xff1a;人物的增删改查 【效果图】 源码 https:…

mysql、redis 、RabbitMQ只能本机访问,怎么改?

如果只能本机访问&#xff0c;怎么改? 一、mysql - 改my.ini 刷脚本 bind-address0.0.0.0 然后重启一下mysql服务 任务管理器-关掉mysql 搜索 计算机管理-重启mysql服务 然后 打开查询&#xff0c;并选择mysql数据&#xff0c;输入这个sql语句&#xff0c;点击运行 sele…

小程序首页轮播图设计

效果图 微信小程序的数据详解 indicator-dots&#xff1a;是否显示面板指示点【默认false 】 indicator-color&#xff1a;指示点颜色【默认rgba(0, 0, 0, .3)】 indicator-active-color&#xff1a;当前选中的指示点颜色【默认#000000】 autoplay&#xff1a;是否自动切换…

总结928

在备考的过程中&#xff0c;我时不时会思考这个问题&#xff0c;我到底怎么样才能“一战成硕”&#xff0c;这个问题本质上就是如何达成目标的问题。 曾遇到这么一句话&#xff0c;90%的人没有目标&#xff0c;99.9%的人败在了目标上。当看到这句话&#xff0c;我还以为是我的…

WEB:upload1

题目 看到文件上传的一般思路是&#xff1a;构建一句话木马&#xff0c;利用bp修改包后缀名&#xff08;一般会限制上传文件类型&#xff09;&#xff0c;上传成功以后注意文件位置&#xff0c;利用菜刀或者是中国蚁剑进行连接&#xff0c; 然后获得flag 构建一句话木马 <…

什么是产品生命周期(PLM)管理系统?

引言 产品生命周期管理 (PLM) 涉及产品生命周期的每个阶段。从产品设计人员进行创造性构思&#xff0c;到物联网网络发送和接收宝贵的数据&#xff0c;再到接收客户真实且及时的反馈&#xff0c;整个产品生命周期中的每一条信息都至关重要&#xff0c;构成了完整的产品构成。 …

【雕爷学编程】Arduino动手做(02)---光敏电阻模块2

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…