展开菜单
首页 精品内容 本月促销 装机必备 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软件 更多
    Aperty macOS版
    Aperty macOS版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw macOS版
    AionClaw macOS版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy macOS版
    Loomy macOS版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

    AirBuddy 3 macOS版
    AirBuddy 3 macOS版

    AirBuddy 3 是面向 macOS 的蓝牙外设增强工具,可集中查看 AirPods、Beats 与苹果设备电量,提供快速连接、播放控制、电量提醒、桌面小组件和多台 Mac 外设接力等功能。

    AirServer macOS版
    AirServer macOS版

    AirServer macOS版可把 Mac 转换为无线投屏接收端,通过 AirPlay 或 Google Cast 接收手机、平板和电脑画面,并支持多设备同时连接、高清镜像及会话录制,适合家庭娱乐、课堂教学、会议演示和应用展示。

    AnyDesk macOS版
    AnyDesk macOS版

    AnyDesk macOS版是一款适用于远程办公、设备维护和客户支持的远程桌面工具,可连接并操作异地计算机,支持文件传输、无人值守访问、会话权限控制及跨平台协作。

    WINDOWS 更多
    讯飞绘文 网页版
    讯飞绘文 网页版

    讯飞绘文网页版是科大讯飞推出的AI图文创作与内容运营工具,覆盖热点选题、文章生成、稿件校对、智能配图、排版发布和数据复盘等环节,适合自媒体创作者及内容团队在线使用。

    Maya(Autodesk Maya) Windows版
    Maya(Autodesk Maya) Windows版

    Autodesk Maya 是面向影视、电视、动画和游戏行业的专业三维制作软件,集多边形与 NURBS 建模、角色绑定、关键帧和动作捕捉动画、Bifrost 特效模拟、材质开发及 Arnold 渲染于一体,

    Aperty Windows版
    Aperty Windows版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw Windows版
    AionClaw Windows版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy Windows版
    Loomy Windows版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

    AirServer Windows版
    AirServer Windows版

    AirServer Windows版可把电脑变成AirPlay、Google Cast和Miracast无线投屏接收端,适合会议演示、课堂教学及家庭大屏分享。发送设备通常无需另装客户端,并可同时接收和智能排列多个镜像会话。