展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 编程开发 > C++获取vector大小方法详解

C++获取vector大小方法详解

要获取std::vector的大小,应调用其.size()成员函数,它返回当前元素数量,时间复杂度为O(1);size()表示实际元素个数,capacity()表示已分配内存可容纳的元素总数,size()≤capacity();通过reserve(n)可预先分配内存避免频繁扩容提升性能,shrink_to_fit()则尝试释放多余容量;需注意扩容会导致迭代器、指针失效,且resize()改变元素数量而reserve()仅改变容量。

本文目录

    要获取std::vector的大小,应调用其.size()成员函数,它返回当前元素数量,时间复杂度为O(1);size()表示实际元素个数,capacity()表示已分配内存可容纳的元素总数,size() ≤ capacity();通过reserve(n)可预先分配内存避免频繁扩容提升性能,shrink_to_fit()则尝试释放多余容量;需注意扩容会导致迭代器、指针失效,且resize()改变元素数量而reserve()仅改变容量。

    如何在C++中获取vector的大小_C++ vector大小与容量管理

    在C++中,要获取std::vector的大小,最直接、最常用的方法就是调用它的成员函数.size()。这个函数会返回vector当前实际包含的元素数量,也就是它当前有多“满”。

    解决方案

    要获取std::vector的大小,我们只需要简单地调用其.size()成员函数即可。这个函数不接受任何参数,并返回一个无符号整型值,通常是std::vector::size_type,它等同于std::size_t。这个返回值精确地告诉我们vector中当前有多少个元素。

    举个例子:

    #include 
    #include 
    #include 
    
    int main() {
        std::vector numbers = {10, 20, 30, 40, 50};
        // 获取vector中元素的数量
        size_t currentSize = numbers.size();
        std::cout << "vector 'numbers' 的当前大小是: " << currentSize << std::endl; // 输出 5
    
        numbers.push_back(60); // 添加一个元素
        std::cout << "添加元素后,vector 'numbers' 的大小是: " << numbers.size() << std::endl; // 输出 6
    
        std::vector words;
        std::cout << "空vector 'words' 的大小是: " << words.size() << std::endl; // 输出 0
    
        if (words.empty()) { // 也可以用empty()来判断是否为空
            std::cout << "'words' vector 是空的。" << std::endl;
        }
    
        return 0;
    }

    .size()是一个非常基础且高频使用的函数,它的时间复杂度是常数级别的(O(1)),所以你可以放心地在任何需要知道vector当前元素数量的地方使用它,不用担心性能问题。

    std::vector的size()与capacity()有什么区别?

    这是个很常见的问题,也常常让人感到困惑。在我看来,理解size()和capacity()是掌握std::vector性能特性的关键。

    size(),就像我们前面提到的,代表的是vector当前实际存储的元素数量。你可以把它想象成你家里的餐桌上实际摆放了多少个盘子。

    而capacity()(容量),则表示vector当前已经分配了多少内存空间,可以容纳多少个元素,而无需重新分配内存。这就像你餐桌的大小,它能摆放的最大盘子数量。

    所以,一个核心的关系是:size() <= capacity()。vector为了提高效率,尤其是当你在末尾频繁添加元素(比如push_back)时,它不会每次都只分配刚刚好的内存。当size()达到capacity()时,vector就需要进行一次“扩容”操作。这个扩容通常会分配一块更大的新内存,然后将旧内存中的所有元素拷贝到新内存中,最后释放旧内存。这个过程是比较耗时的。

    举个例子,你有一个vector,初始容量可能是10。当你push_back第11个元素时,vector会发现当前容量不够了,它可能会分配一个容量为20的新内存块,把之前的10个元素复制过去,再把第11个元素放进去。这样,在接下来的9次push_back操作中,就不需要再扩容了。这种策略就是为了实现push_back的摊销常数时间复杂度。

    #include 
    #include 
    
    int main() {
        std::vector data;
    
        std::cout << "初始状态: size = " << data.size() << ", capacity = " << data.capacity() << std::endl;
    
        for (int i = 0; i < 10; ++i) {
            data.push_back(i);
            // 观察size和capacity的变化
            std::cout << "添加 " << i << ": size = " << data.size() << ", capacity = " << data.capacity() << std::endl;
        }
    
        // 假设在我的系统上,vector的扩容策略是翻倍
        // 当size达到capacity时,capacity会翻倍
        // 比如:0, 1, 2, 4, 8, 16...
        // 每次capacity变化都意味着一次内存重新分配和元素拷贝
        return 0;
    }

    通过观察上面的输出,你会发现capacity并不是每次push_back都会增加,它只会在size等于capacity时才增加,而且通常会以倍数增长。

    vector的容量管理策略:reserve()与shrink_to_fit()

    既然我们知道了capacity的存在以及扩容的开销,那么自然就会想到如何主动管理它,避免不必要的性能损耗。这里就引入了reserve()和shrink_to_fit()。

    reserve(n):这个函数是用来预留空间的。当你明确知道vector最终大概会包含多少个元素时,或者在一个循环中会频繁push_back大量元素时,提前调用reserve(n)可以一次性分配足够的内存,使得在后续的n次push_back操作中,vector无需再进行内存重新分配和元素拷贝。这对于性能敏感的代码来说,是个非常有效的优化手段。

    #include 
    #include 
    #include  // 用于测量时间
    
    int main() {
        std::vector numbers;
        const int num_elements = 1000000;
    
        // 不使用reserve()
        auto start_no_reserve = std::chrono::high_resolution_clock::now();
        for (int i = 0; i < num_elements; ++i) {
            numbers.push_back(i);
        }
        auto end_no_reserve = std::chrono::high_resolution_clock::now();
        std::chrono::duration diff_no_reserve = end_no_reserve - start_no_reserve;
        std::cout << "不使用reserve(),添加 " << num_elements << " 个元素耗时: " << diff_no_reserve.count() << " 秒" << std::endl;
        numbers.clear(); // 清空,准备下一次测试
    
        // 使用reserve()
        auto start_reserve = std::chrono::high_resolution_clock::now();
        numbers.reserve(num_elements); // 提前预留空间
        for (int i = 0; i < num_elements; ++i) {
            numbers.push_back(i);
        }
        auto end_reserve = std::chrono::high_resolution_clock::now();
        std::chrono::duration diff_reserve = end_reserve - start_reserve;
        std::cout << "使用reserve(),添加 " << num_elements << " 个元素耗时: " << diff_reserve.count() << " 秒" << std::endl;
    
        // 你会发现使用reserve()通常会快很多
        return 0;
    }

    通过上面的测试,你会直观地感受到reserve()带来的性能提升。

    shrink_to_fit():与reserve()相反,shrink_to_fit()是用来尝试减少vector的容量,使其容量尽可能地与当前size()匹配。当你vector中删除了大量元素,或者vector在某个阶段达到了一个很大的容量,但现在实际使用的元素很少时,多余的内存就成了浪费。调用shrink_to_fit()可以请求vector释放这些多余的内存。

    需要注意的是,shrink_to_fit()只是一个“请求”,标准并没有强制要求vector必须收缩其容量。具体是否收缩以及收缩到什么程度,取决于具体的标准库实现。但在大多数现代C++标准库中,它通常会尝试将容量调整到size()的大小。

    #include 
    #include 
    
    int main() {
        std::vector data;
        data.reserve(100); // 预留100个空间
        for (int i = 0; i < 5; ++i) {
            data.push_back(i);
        }
        std::cout << "填充少量元素后: size = " << data.size() << ", capacity = " << data.capacity() << std::endl; // size=5, capacity=100
    
        data.shrink_to_fit(); // 尝试收缩容量
        std::cout << "调用shrink_to_fit()后: size = " << data.size() << ", capacity = " << data.capacity() << std::endl; // size=5, capacity可能变为5
    
        return 0;
    }

    shrink_to_fit()在内存敏感的应用中很有用,但它本身也可能涉及内存重新分配和拷贝,所以不应频繁调用,而是在vector生命周期中,当其大小稳定下来且多余容量显著时考虑使用。

    vector大小调整的常见陷阱与性能考量

    对vector的大小和容量管理不当,很容易踩到一些坑,或者导致不必要的性能开销。

    1. 频繁的内存重新分配:这是最主要的性能陷阱。每次capacity不足以容纳新元素而发生扩容时,都会涉及:

      • 分配一块新的更大内存。
      • 将所有现有元素从旧内存复制到新内存。
      • 释放旧内存。 这个过程在元素数量庞大时会非常耗时。这就是为什么reserve()如此重要。
    2. 迭代器、指针和引用的失效:当vector发生扩容(即capacity改变)时,由于底层内存块可能被移动到新的位置,所有指向vector内部元素的迭代器、指针和引用都会失效。这意味着它们不再指向有效的内存地址,继续使用它们会导致未定义行为(通常是程序崩溃)。

      #include 
      #include 
      
      int main() {
          std::vector nums = {1, 2, 3};
          int* p_first = &nums[0]; // 指向第一个元素的指针
          std::cout << "原始第一个元素: " << *p_first << std::endl; // 1
      
          // 此时nums的capacity可能很小,比如3或4
          // 连续push_back可能导致扩容
          nums.push_back(4);
          nums.push_back(5); // 假设这次push_back导致了扩容
      
          // 此时p_first可能已经失效了,因为它指向的内存可能已经被释放
          // 尝试访问它可能导致段错误或其他未定义行为
          // std::cout << "扩容后第一个元素 (可能失效): " << *p_first << std::endl; // 危险操作!
      
          // 正确的做法是重新获取指针或迭代器
          p_first = &nums[0];
          std::cout << "扩容后重新获取的第一个元素: " << *p_first << std::endl; // 1
          return 0;
      }

      这个陷阱非常隐蔽,尤其是在大型项目中,一个看似无害的push_back可能在某个特定条件下触发扩容,导致之前保存的迭代器或指针失效,从而引发难以追踪的bug。

    3. resize()与reserve()的混淆:

      • resize(n):改变vector的size()。如果n大于当前size(),vector会添加新元素,并用默认构造函数(或指定值)初始化它们;如果n小于当前size(),vector会删除多余的元素。resize()也可能导致扩容。
      • reserve(n):只改变vector的capacity(),不改变size(),也不会添加或删除元素。它只是预留了内存。 理解两者的区别至关重要。如果你只是想预留空间以提高后续插入的效率,使用reserve();如果你想改变vector的实际元素数量并可能初始化它们,使用resize()。
    4. clear()与erase():

      • clear():将vector的size()设置为0,但通常不会改变capacity()。这意味着它清空了所有元素,但保留了已分配的内存,下次再添加元素时可以复用。
      • erase():删除指定范围的元素,size()会相应减少,capacity()通常不会改变。 如果你需要彻底释放vector占用的所有内存(包括容量),一个常见的技巧是: std::vector().swap(myVector); 这会创建一个临时的空vector,然后与myVector交换,myVector就变成了空的且容量为0,而旧的myVector(现在是临时的空vector)在语句结束时被销毁,从而释放了内存。

    总之,高效地使用std::vector不仅仅是知道如何获取其大小,更重要的是理解其背后的内存管理机制。合理地使用reserve()来避免不必要的扩容,注意迭代器失效的问题,并根据实际需求选择resize()、clear()或shrink_to_fit(),这些都是编写健壮、高性能C++代码的重要实践。

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发
    相关文章 更多
    精品专题 更多
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    macOS软件

    正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

    IOS软件

    正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

    AI

    正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

    Mac软件 更多
    Postman macOS版
    Postman macOS版

    Postman是一套面向API全生命周期的开发与测试平台,可在Mac上发送和调试多种协议请求,管理集合、环境及认证信息,并完成脚本测试、模拟服务、监控、文档发布和团队协作。它适合开发、测试及运维人员使用,提供个人免费方案。

    Docker Desktop macOS版
    Docker Desktop macOS版

    Docker Desktop 是 Docker 官方为 Mac 提供的容器开发环境,集成 Docker Engine、命令行工具、Compose、Build、Kubernetes 与图形化管理界面。

    Android Studio macOS版
    Android Studio macOS版

    Android Studio 是 Google 面向安卓应用开发提供的官方集成开发环境,基于 IntelliJ IDEA 构建。它整合智能代码编辑、Gradle 构建、界面预览、设备模拟、性能分析、调试测试及 APK 分析等工具。

    Xcode macOS版
    Xcode macOS版

    Xcode 是苹果面向 Mac 提供的官方集成开发环境,将代码编辑、项目构建、SwiftUI 实时预览、设备模拟、自动化测试、断点调试、性能分析和应用分发整合在同一套工作流中,适合开发与维护 iPhone、iPad、Mac、Apple Wa

    JetBrains WebStorm macOS版
    JetBrains WebStorm macOS版

    JetBrains WebStorm 是面向 JavaScript、TypeScript 和现代 Web 技术的专业集成开发环境,可智能理解项目结构,提供代码补全、重构、错误检查、运行调试、测试及 Git 工具。

    PhpStorm macOS版
    PhpStorm macOS版

    PhpStorm 是 JetBrains 推出的专业 PHP 集成开发环境,可在 Mac 上完成代码编写、智能检查、重构、调试、测试和数据库管理。它支持主流 PHP 框架、Composer、Git、Docker 与远程解释器。

    JetBrains PyCharm macOS版
    JetBrains PyCharm macOS版

    JetBrains PyCharm 是面向 Python 开发者的集成开发环境,提供智能补全、代码检查、重构、调试、测试、版本控制及虚拟环境管理功能。Mac 版兼容 Intel 与 Apple 芯片,核心功能可免费使用。

    JetBrains IntelliJ IDEA macOS版
    JetBrains IntelliJ IDEA macOS版

    IntelliJ IDEA 是 JetBrains 推出的专业集成开发环境,重点服务于 Java、Kotlin 与 JVM 项目开发。软件集成代码补全、静态检查、重构、调试、测试、版本控制及构建工具,并可借助插件扩展语言和框架支持。

    Visual Studio Code macOS版
    Visual Studio Code macOS版

    Visual Studio Code 是微软提供的免费代码编辑器,支持 macOS,并为 Intel 与 Apple 芯片 Mac 提供适配版本。软件集代码编辑、调试、Git 源代码管理、集成终端和扩展市场于一体。

    REAPER macOS版
    REAPER macOS版

    REAPER是Cockos开发的数字音频工作站,提供多轨音频与MIDI录制、剪辑、处理、混音和母带制作工具。Mac版兼容Intel与Apple芯片,支持AU、VST、VST3、CLAP等插件格式,并提供高度可定制的工作流程。

    Adobe Audition macOS版
    Adobe Audition macOS版

    Adobe Audition 是面向播客、影视后期、音乐制作及内容创作者的专业音频工作站,提供波形精修、多轨录制与混音、频谱编辑、降噪修复、响度匹配和效果处理工具,并可与 Adobe Premiere 协同完成视频声音制作。

    Pro Tools macOS版
    Pro Tools macOS版

    Pro Tools 是 Avid 推出的专业数字音频工作站,覆盖多轨录音、无损剪辑、MIDI 编曲、插件处理、自动化混音及声音与画面同步等工作。它拥有 Intro、Artist、Studio 和 Ultimate 等方案。

    WINDOWS 更多
    PixPix 网页版
    PixPix 网页版

    PixPix 是面向品牌、卖家和内容团队的在线 AI 图片视频创作平台,提供图视频 Agent、无限画布、图片生成、视频生成、自然语言编辑及商品套图、产品精修和带货视频等电商工具。

    Postman Windows版
    Postman Windows版

    Postman 是面向 API 全生命周期的开发与协作平台。Windows 桌面版可用于构建和发送 HTTP、GraphQL、gRPC、WebSocket、MQTT 等请求,并提供环境变量、集合、脚本测试、模拟服务、监控、文档及团队工作区等

    Docker Desktop Windows版
    Docker Desktop Windows版

    Docker Desktop 为 Windows 开发者提供集成式容器环境,内置 Docker Engine、命令行工具、Compose、Build 与 Kubernetes 等组件,可在本机完成镜像构建、容器运行、日志查看和资源管理。

    Android Studio Windows版
    Android Studio Windows版

    Android Studio 是 Google 面向 Android 应用开发提供的官方集成开发环境,以 IntelliJ IDEA 为基础,集成智能代码编辑、Gradle 构建、设备模拟、界面预览、调试测试及性能分析工具,

    JetBrains WebStorm Windows版
    JetBrains WebStorm Windows版

    WebStorm 是 JetBrains 面向 JavaScript、TypeScript 和现代 Web 技术打造的集成开发环境。它提供项目级代码分析、智能补全、安全重构、导航搜索,并集成调试、测试、终端、Git 与常用前端工具,

    JetBrains PhpStorm Windows版
    JetBrains PhpStorm Windows版

    PhpStorm 是 JetBrains 面向 PHP 与现代 Web 开发打造的专业集成开发环境,提供代码补全、静态检查、重构、调试、测试、数据库、版本控制及前端语言支持。Windows 用户可直接下载安装程序,

    JetBrains PyCharm Windows版
    JetBrains PyCharm Windows版

    PyCharm 是 JetBrains 推出的 Python 集成开发环境,提供智能代码补全、错误检查、重构、调试、测试、Git、终端及 Jupyter Notebook 支持。统一版安装后可体验 30 天 Pro 功能,

    JetBrains IntelliJ IDEA Windows版
    JetBrains IntelliJ IDEA Windows版

    JetBrains IntelliJ IDEA 是以 Java、Kotlin 和 JVM 项目为核心的专业集成开发环境,提供智能补全、代码检查、安全重构、调试、测试、版本控制及构建工具集成。统一发行版的核心功能可免费用于商业和非商业项目,

    Visual Studio Code Windows版
    Visual Studio Code Windows版

    Visual Studio Code 是微软推出的免费代码编辑器,Windows 版集成智能补全、代码导航、调试、终端和版本控制,并可通过扩展添加语言、格式化及远程开发能力。它启动较快、配置灵活,

    REAPER Windows版
    REAPER Windows版

    REAPER 是 Cockos 推出的数字音频工作站,适用于录音、MIDI 编曲、音频编辑、混音、母带制作及声音设计。软件安装包小巧,支持多轨录制、灵活路由、自动化、第三方插件和脚本扩展,并提供完整功能的 60 天免费评估期。

    Adobe Audition Windows版
    Adobe Audition Windows版

    Adobe Audition 是面向播客、影视后期、广播与音乐制作的专业音频工作站,提供波形编辑、多轨混音、频谱分析、录音、降噪修复和效果处理等功能。Windows 版通过 Adobe Creative Cloud 安装和管理,

    Pro Tools Windows版
    Pro Tools Windows版

    Pro Tools 是 Avid 推出的专业数字音频工作站,提供多轨录音、音频剪辑、MIDI编曲、插件处理、自动化混音及影视声音制作能力。它适合音乐人、录音师、制作人和音频后期团队使用,并提供免费入门版、订阅方案及永久授权选择。