C++ vector容器存储对象和存储指针的区别(vector对象、vector指针)(存储指针时推荐使用智能指针)

news2025/6/9 19:16:13

文章目录

      • **1. 内存管理**
        • - **存储对象**:
        • - **存储指针**:
      • **2. 生命周期控制**
        • - **存储对象**:
        • - **存储指针**:
      • **3. 性能差异**
        • - **存储对象**:
        • - **存储指针**:
      • **4. 使用场景**
        • - **选择存储对象的情况**:
        • - **选择存储指针的情况**:
      • **5. 注意事项**
        • - **存储指针的风险**:
        • - **推荐实践**:
          • - 使用智能指针(如 `std::unique_ptr`、`std::shared_ptr`)替代原始指针,自动管理内存:
      • **6. 总结对比表**
      • **7. 示例代码**
        • - **存储对象**:
        • - **存储指针**:

在 C++ 中, std::vector 容器存储对象(如 int、自定义类实例)和指针(如 int*MyClass*)时,存在显著差异,主要体现在 内存管理、生命周期控制、性能开销使用场景 上。以下是详细对比:


1. 内存管理

- 存储对象
  • vector 管理对象的完整生命周期。
  • vector 被销毁或调用 clear() 时,所有对象会自动调用析构函数,内存被释放。
  • 示例:
    std::vector<MyClass> vec;
    vec.push_back(MyClass()); // 存储对象
    vec.clear();              // 自动释放所有对象内存
    
- 存储指针
  • vector 仅管理指针本身的生命周期,不负责释放指针指向的对象
  • 需要手动遍历 vectordelete 每个指针指向的对象,否则会导致内存泄漏。
  • 示例:
    std::vector<MyClass*> vec;
    vec.push_back(new MyClass()); // 存储指针
    for (auto* ptr : vec) delete ptr; // 手动释放内存
    vec.clear();                    // 仅释放指针本身
    

2. 生命周期控制

- 存储对象
  • vector 的扩容(如 push_back 超过容量时)会复制或移动对象到新内存区域,原对象被析构。
  • 示例:
    std::vector<std::string> vec;
    vec.push_back("hello"); // 如果扩容,"hello" 会被复制到新内存
    
- 存储指针
  • vector 扩容时仅复制指针(地址),不会影响指针指向的对象
  • 指针指向的对象生命周期需独立管理,与 vector 无关。
  • 示例:
    std::vector<MyClass*> vec;
    MyClass* obj = new MyClass();
    vec.push_back(obj); // 存储指针
    // 即使 vec 扩容,obj 的内存地址不会改变
    

3. 性能差异

- 存储对象
  • 优点:直接存储对象,访问效率高(连续内存,缓存友好)。
  • 缺点:对象较大时,频繁扩容可能导致大量复制开销(需调用拷贝构造函数)。
  • 适合场景:对象较小或频繁访问,且不需要动态分配内存。
- 存储指针
  • 优点:避免对象复制开销(仅复制指针地址)。
  • 缺点:需要手动管理内存(new/delete),且指针访问可能因内存不连续导致缓存效率低。
  • 适合场景:对象较大或需要共享所有权(如多 vector 共同管理同一对象)。

4. 使用场景

- 选择存储对象的情况
  • 对象生命周期与 vector 绑定,无需共享。
  • 需要频繁访问或修改对象,且对象较小。
  • 示例:存储基本类型(intfloat)或小型结构体。
- 选择存储指针的情况
  • 对象需要动态分配(如通过 new 创建)。
  • 需要共享对象所有权(多个 vector 或其他容器指向同一对象)。
  • 对象较大,复制成本高。
  • 示例:存储多态对象(基类指针指向派生类实例)。

5. 注意事项

- 存储指针的风险
  1. 内存泄漏:忘记 delete 指针会导致内存泄漏。
  2. 悬空指针:若 vector 管理的指针指向的对象被提前释放,后续访问会导致未定义行为。
  3. 重复释放:如知识库 [1] 提到的 double free 错误(例如在类析构函数中调用 vector<T>().swap() 释放指针)。
- 推荐实践
- 使用智能指针(如 std::unique_ptrstd::shared_ptr)替代原始指针,自动管理内存:
std::vector<std::unique_ptr<MyClass>> vec;
vec.push_back(std::make_unique<MyClass>());
// 不需要手动 delete,vec 析构时自动释放

6. 总结对比表

特性存储对象存储指针
内存管理自动释放需手动 delete
生命周期绑定vector 绑定独立于 vector
扩容开销复制对象(调用拷贝/移动构造函数)仅复制指针地址
访问效率高(连续内存)低(间接访问)
适用场景对象小、生命周期短对象大、需要共享所有权或动态分配
风险无(除非自定义析构逻辑)内存泄漏、悬空指针、重复释放

7. 示例代码

- 存储对象
#include <vector>
struct MyClass {
    MyClass() { printf("Constructor\n"); }
    ~MyClass() { printf("Destructor\n"); }
};
int main() {
    std::vector<MyClass> vec;
    vec.push_back(MyClass()); // 对象被复制到 vector 中
    vec.clear();              // 自动调用析构函数
}
- 存储指针
#include <vector>
struct MyClass {
    MyClass() { printf("Constructor\n"); }
    ~MyClass() { printf("Destructor\n"); }
};
int main() {
    std::vector<MyClass*> vec;
    vec.push_back(new MyClass()); // 手动分配内存
    for (auto* ptr : vec) delete ptr; // 必须手动释放
    vec.clear();
}

通过以上对比,可以根据具体需求选择存储对象或指针。在现代 C++ 中,优先推荐使用智能指针来避免手动内存管理的风险。

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

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

相关文章

50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | Dad Jokes(冷笑话卡片)

&#x1f4c5; 我们继续 50 个小项目挑战&#xff01;—— DadJokes 组件 仓库地址&#xff1a;https://github.com/SunACong/50-vue-projects 项目预览地址&#xff1a;https://50-vue-projects.vercel.app/ 豆包翻译确实可以&#xff0c;冷笑话应该属于各类语言比较难理解的…

Spring AOP执行原理源码解析

对【com.example.demo.TestAspect#aopTest】连接点增加了五个通知 在调用【com.example.demo.A#testAop()】&#xff08;用户自定义&#xff09;方法时&#xff0c;Cglib拦截器对其进行了拦截 可以看到执行顺序分别是环绕前置&#xff0c;前置&#xff0c;环绕后置&#xff0c;…

基于FPGA的超声波显示水位距离,通过蓝牙传输水位数据到手机,同时支持RAM存储水位数据,读取数据。

基于FPGA的超声波显示水位距离 前言一、整体框架二、代码架构1.超声波测距模块2.蓝牙数据发送模块3.数码管数据切换模块4.数码管驱动模块6.串口驱动7.顶层模块8.RAM ip核 仿真相关截图 前言 随着工业化进程的加速和环境保护意识的提升&#xff0c;对水资源管理和水位监测的需求…

在Windows下利用LoongArch-toolchain交叉编译Qt

文章目录 0.交叉编译的必要性1.下载交叉编译工具链1.1.直接在Windows下使用mingw&#xff08;不使用虚拟机&#xff09;编译&#xff08;还没成功&#xff0c;无法编译&#xff09;1.2.在虚拟机中的Ubuntu中进行交叉编译 2.下载qt源码3.编译Qt3.1.创建loongarch64的mkspec3.2.创…

AIRIOT无人机安防解决方案

随着无人机技术的飞速发展和广泛应用&#xff0c;其在安防领域的价值日益凸显&#xff0c;从关键设施巡检、大型活动安保到边境巡防、应急救援&#xff0c;无人机正成为立体化安防体系不可或缺的“空中哨兵”。然而&#xff0c;无人机安防应用蓬勃发展的同时&#xff0c;其自身…

华为OD机考 - 水仙花数 Ⅰ(2025B卷 100分)

import java.util.*; public static Integer get(int count,int c){if(count<3||count>7){return -1;}//存储每位数的最高位……最低位int[] arr new int[count];List<Integer> res new ArrayList<>();for(int i(int) Math.pow(10,count-1);i<(int) Math…

php apache构建 Web 服务器

虚拟机配置流程winsever2016配置Apache、Mysql、php_windows server 2016配置web服务器-CSDN博客 PHP 和 Apache 通过 ​​模块化协作​​ 共同构建 Web 服务器&#xff0c;以下是它们的交互机制和工作流程&#xff1a; ​​一、核心组件分工​​ 组件角色​​Apache​​Web …

打通印染车间“神经末梢”:DeviceNet转Ethernet/IP连接机器人的高效方案

在印染行业自动化升级中&#xff0c;设备联网需求迫切。老旧印染设备多采用Devicenet协议&#xff0c;而新型工业机器人普遍支持Ethernet/IP协议&#xff0c;协议不兼容导致数据交互困难&#xff0c;设备协同效率低、生产监控滞后&#xff0c;成了行业数字化转型的阻碍。本文将…

2025-06-02-IP 地址规划及案例分析

IP 地址规划及案例分析 参考资料 Plan for IP addressing - Cloud Adoption Frameworkwww.cnblogs.comimage-hosting/articles at master jonsam-ng/image-hosting 概述 在网络通信中&#xff0c;MAC 地址与 IP 地址分别位于 OSI 模型的数据链路层和网络层&#xff0c;二者协…

AUTOSAR实战教程--开放式通用DoIP刷写工具OpenOTA开发计划

目录 软件概述 安装与运行 界面说明 3.1 功能区划分 3.2 状态显示 基本操作流程 4.1 DoIP连接配置 4.2 服务配置&#xff08;刷写流程&#xff09; 4.3 执行操作 4.4 保存配置 4.5 加载配置 功能详解 5.1 核心功能模块 诊断服务配置 通信设置 文件下载 工具功…

AI赋能的浏览器自动化:Playwright MCP安装配置与实操案例

以下是对Playwright MCP的简单介绍&#xff1a; Playwright MCP 是一个基于 Playwright 的 MCP 工具&#xff0c;提供浏览器自动化功能不要求视觉模型支持&#xff0c;普通的文本大语言模型就可以通过结构化数据与网页交互支持多种浏览器操作&#xff0c;包括截图、点击、拖动…

【技术笔记】MSYS2 指定 Python 版本安装方案

#工作记录 MSYS2 指定 Python 版本安装 一、前置条件 安装指定版本需要在干净的 MSYS2 环境中执行&#xff0c;为保证工具链的兼容性&#xff0c;若已安装 Python&#xff0c;需先卸载 Python 及与该版本深度绑定的工具链。具体操作如下&#xff1a; 卸载 Python&#xff1a…

《校园生活平台从 0 到 1 的搭建》第一篇:创建项目与构建目录结构

在本系列第一篇中&#xff0c;我们将从项目初始化开始&#xff0c;搭建基本的目录结构&#xff0c;并完成四个主页面的创建与 TabBar 设置。 &#xff08;tip&#xff1a;你可能会觉得有点 ai 化&#xff0c;因为这个文案是我自己写了一遍文案之后让 ai 去优化输出的&#xff0…

1 Studying《蓝牙核心规范5.3》

目录 [Vol 0][Part B 蓝牙规范要求] 3 定义 3.1 蓝牙产品类型 4 核心配置 4.1 基本速率核心配置 4.2 增强型数据速率核心配置 4.4 低功耗核心配置 4.5 基本速率和低功耗结合的核心配置 4.6 主机控制器接口核心配置 [Vol 1][Part A 架构]1 概述 1.1 BR/EDR操作概述 …

STM32+MPU6050传感器

#创作灵感## 在嵌入式系统开发中&#xff0c;STM32F103C8T6单片机与MPU6050传感器的组合因其高性能、低功耗以及丰富的功能而备受青睐。本文将简单介绍如何在Keil 5开发环境中实现STM32F103C8T6与MPU6050的连接和基本数据采集&#xff0c;带你快速入门智能硬件开发。 一、硬件…

26考研——数据的表示和运算_整数和实数的表示(2)

408答疑 文章目录 二、整数和实数的表示1、整数的表示1.1、无符号整数的表示1.2、有符号整数的表示1.3、C 语言中的整数类型及类型转换1.3.1、C 语言中的整型数据类型1.3.2、有符号数和无符号数的转换1.3.3、不同字长整数之间的转换 2、实数的表示2.1、浮点数的相关概念2.2、浮…

关于智能体API参考接口

关于智能体在Flask的源码&#xff1a;请求体(在payload里的是请求体)、请求头&#xff08;在headers里的i局势请求头&#xff09;。 我的例子&#xff1a; 我的疑问&#xff1a;为什么没按Coze官方API文档格式&#xff0c;在Apifox里发POST请求却能收到回复&#xff1f; 1. 你…

直角坐标系和斜角坐标系

前情概要 笛卡尔坐标系是直角坐标系和斜角坐标系的统称。为什么会有这两种坐标系呢&#xff0c;教材中为什么最后只用直角坐标系呢&#xff1f;我们这样解释&#xff1a; 研究一维空间中的向量时&#xff0c;由于一维空间中的向量有无数条&#xff0c;如果我们选定一条作为基…

vmware 设置 dns

vmware 设置 dns 常用的 DNS&#xff08;Domain Name System&#xff09;服务器地址可以帮助你更快、更安全地解析域名。以下是一些国内外常用的公共 DNS 服务&#xff1a; 国内常用 DNS 阿里云 DNS IPv4: 223.5.5.5、223.6.6.6IPv6: 2400:3200::1、2400:3200:baba::1特点&am…

基于单片机的病房呼叫系统(源码+仿真)

该系统由以 STM32F4 为平台的监控终端以及以 CC2530 为平台的无线传感网组成。系统上电后自动完成 ZigBee 网络的组建、终端节点的加入&#xff0c;病人可利用便携式的病人终端发出呼叫求助请求信息、节点在线信息以及对护士的服务评价信息等&#xff0c;这些信息通过路由节点发…