std::vector<>.emplace_back

emplace_back() 详解:C++ 就地构造的效率革命

emplace_back() 是 C++11 引入的容器成员函数,用于在容器尾部就地构造(而非拷贝或移动)元素。这一特性显著提升了复杂对象的插入效率,尤其适用于构造代价较高的类型。

一、核心优势:就地构造,避免拷贝

传统的 push_back() 需要先构造一个临时对象,再将其拷贝或移动到容器中:

std::vector<std::string> vec;
vec.push_back("hello");  // 步骤1: 构造临时 string 对象// 步骤2: 移动临时对象到 vector 中// 步骤3: 销毁临时对象

emplace_back() 直接在容器尾部的内存空间中构造对象:

vec.emplace_back("hello");  // 直接在 vector 内存中构造 string 对象// 无需临时对象,无需拷贝/移动

二、参数与原理

emplace_back() 的原型为:

template <class... Args>
void emplace_back(Args&&... args);
  • 参数Args&&... args 是一个可变参数模板,接受任意数量和类型的参数
  • 原理:通过完美转发(Perfect Forwarding)将参数传递给元素类型的构造函数
  • 效果:直接在容器管理的内存中构造对象,无需临时对象

三、示例对比

1. 基本类型示例
std::vector<int> vec;
vec.push_back(42);          // 拷贝 int 值
vec.emplace_back(42);       // 直接构造 int 值// 两者效率相同,因为 int 是 POD 类型
2. 复杂对象示例
class ExpensiveObject {
public:ExpensiveObject(int x, double y) : x(x), y(y) {// 复杂且耗时的初始化操作}// 拷贝构造函数(代价高)ExpensiveObject(const ExpensiveObject& other) = delete;// 移动构造函数(代价高)ExpensiveObject(ExpensiveObject&& other) = delete;
};std::vector<ExpensiveObject> vec;// 错误:无法使用 push_back,因为需要拷贝或移动
// vec.push_back(ExpensiveObject(1, 2.0));// 正确:emplace_back 直接构造对象
vec.emplace_back(1, 2.0);  // 直接传递构造参数

四、完美转发与参数匹配

emplace_back() 支持直接传递构造所需的参数,包括:

  1. 构造函数参数
  2. 初始化列表
  3. 隐式类型转换参数
class Person {
public:Person(std::string name, int age) : name(name), age(age) {}private:std::string name;int age;
};std::vector<Person> people;// 使用 emplace_back 传递构造参数
people.emplace_back("Alice", 30);  // 直接构造 Person 对象// 使用 push_back 需要显式构造 Person
people.push_back(Person("Bob", 25));  // 先构造临时对象,再移动

五、与 push_back() 的关键区别

特性emplace_back()push_back()
参数接受构造函数的参数包接受已构造的对象(左值或右值)
构造方式就地构造,无需临时对象需要先构造临时对象,再拷贝/移动
支持不可移动类型支持(只要构造函数可用)不支持(必须可拷贝或可移动)
隐式类型转换支持(直接传递转换所需参数)需显式转换(或提供转换构造函数)

六、注意事项

  1. 内存扩容:若容器需要重新分配内存,emplace_back() 仍需移动所有现有元素

  2. 异常安全:若构造函数抛出异常,容器状态保持不变

  3. 返回值emplace_back() 不返回新元素的引用(C++17 起 emplace() 返回)

  4. 优先使用场景

    • 插入复杂对象(如包含动态资源的类)
    • 插入需要隐式类型转换的对象
    • 插入不可拷贝/不可移动的对象

七、进阶应用:初始化列表参数

emplace_back() 可以正确处理初始化列表参数:

std::vector<std::vector<int>> matrix;// 使用 emplace_back 和初始化列表
matrix.emplace_back({1, 2, 3});  // 直接构造内部 vector// 等价于
matrix.push_back(std::vector<int>{1, 2, 3});

八、性能测试对比

以下代码对比了 push_backemplace_back 的性能差异:

#include <chrono>
#include <vector>
#include <string>
#include <iostream>struct ExpensiveToCopy {std::string largeData;ExpensiveToCopy(const char* data) : largeData(data) {}// 模拟高代价的拷贝构造ExpensiveToCopy(const ExpensiveToCopy& other) : largeData(other.largeData) {// 模拟耗时操作for (int i = 0; i < 1000; ++i) {}}
};int main() {std::vector<ExpensiveToCopy> vec;// 测试 push_backauto start = std::chrono::high_resolution_clock::now();for (int i = 0; i < 10000; ++i) {vec.push_back("a very long string that needs to be copied");}auto end = std::chrono::high_resolution_clock::now();std::cout << "push_back time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()<< " ms" << std::endl;// 测试 emplace_backvec.clear();start = std::chrono::high_resolution_clock::now();for (int i = 0; i < 10000; ++i) {vec.emplace_back("a very long string that needs to be copied");}end = std::chrono::high_resolution_clock::now();std::cout << "emplace_back time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()<< " ms" << std::endl;return 0;
}

九、总结

emplace_back() 是 C++ 容器库的重要改进,它通过就地构造机制显著提升了插入效率,尤其适用于:

  1. 构造代价高昂的对象
  2. 需要隐式类型转换的对象
  3. 不可拷贝/不可移动的对象

在现代 C++ 编程中,建议优先使用 emplace_back() 替代 push_back(),除非需要明确的类型检查或兼容性保证。

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

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

相关文章

Dify实战案例《AI面试官》更新,支持语音交互+智能知识库+随机题库+敏感词过滤等...

大模型应用课又更新了&#xff0c;除了之前已经完结的两门课&#xff08;视频图文&#xff09;&#xff1a; 《Spring AI 从入门到精通》《LangChain4j 从入门到精通》 还有目前正在更新的 《Dify 从入门到实战》 本周也迎来了一大波内容更新&#xff0c;其中就包括今天要介绍…

AGI大模型(29):LangChain Model模型

1 LangChain支持的模型有三大类 大语言模型(LLM) ,也叫Text Model,这些模型将文本字符串作为输入,并返回文本字符串作为输出。聊天模型(Chat Model),主要代表Open AI的ChatGPT系列模型。这些模型通常由语言模型支持,但它们的API更加结构化。具体来说,这些模型将聊天消…

动态IP技术在跨境电商中的创新应用与战略价值解析

在全球化4.0时代&#xff0c;跨境电商正经历从"流量红利"向"技术红利"的深度转型。动态IP技术作为网络基础设施的关键组件&#xff0c;正在重塑跨境贸易的运营逻辑。本文将从技术架构、应用场景、创新实践三个维度&#xff0c;揭示动态IP如何成为跨境电商突…

android双屏之副屏待机显示图片

摘要&#xff1a;android原生有双屏的机制&#xff0c;但需要芯片厂商适配框架后在底层实现。本文在基于芯发8766已实现底层适配的基础上&#xff0c;仅针对上层Launcher部分对系统进行改造&#xff0c;从而实现在开机后副屏显示一张待机图片。 副屏布局 由于仅显示一张图片&…

STM32之中断

一、提高程序实时性的架构方案 轮询式 指的是在程序运行时&#xff0c;首先对所有的硬件进行初始化&#xff0c;然后在主程序中写一个死循环&#xff0c;需要运行的功能按照顺序进行执行&#xff0c;轮询系统是一种简单可靠的方式&#xff0c;一般适用于在只需要按照顺序执行…

LLM应用开发平台资料

课程和代码资料 放下面了&#xff0c;自取&#xff1a; https://pan.quark.cn/s/57a9d22d61e9

硬盘健康检测与性能测试的实践指南

在日常使用 Windows 系统的过程中&#xff0c;我们常常需要借助各种工具来优化性能、排查问题或管理文件。针对windows工具箱进行实测解析&#xff0c;发现它整合了多种实用功能&#xff0c;能够帮助用户更高效地管理计算机。 以下为测试发现的功能特性&#xff1a; 硬件信息查…

正则表达式进阶(三):递归模式与条件匹配的艺术

在正则表达式的高级应用中&#xff0c;递归模式和条件匹配是处理复杂嵌套结构和动态模式的利器。它们突破了传统正则表达式的线性匹配局限&#xff0c;能够应对嵌套括号、HTML标签、上下文依赖等复杂场景。本文将详细介绍递归模式&#xff08;(?>...)、 (?R) 等&#xff0…

从零开始创建React项目及制作页面

一、React 介绍 React 是一个由 Meta&#xff08;原Facebook&#xff09; 开发和维护的 开源JavaScript库&#xff0c;主要用于构建用户界面&#xff08;User Interface, UI&#xff09;。它是前端开发中最流行的工具之一&#xff0c;广泛应用于单页应用程序&#xff08;SPA&a…

【前端部署】通过 Nginx 让局域网用户访问你的纯前端应用

在日常前端开发中&#xff0c;我们常常需要快速将本地的应用展示给局域网内的同事或测试人员&#xff0c;而传统的共享方式往往效率不高。本文将指导你轻松地将你的纯前端应用&#xff08;无论是 Vue, React, Angular 或原生项目&#xff09;部署到本地&#xff0c;并配置局域网…

【Python装饰器深潜】从语法糖到元编程的艺术

目录 🌟 前言🏗️ 技术背景与价值🩹 当前技术痛点🛠️ 解决方案概述👥 目标读者说明🧠 一、技术原理剖析📊 核心概念图解💡 核心作用讲解🔧 关键技术模块说明⚖️ 技术选型对比🛠️ 二、实战演示⚙️ 环境配置要求💻 核心代码实现案例1:基础计时装饰器案…

mbed驱动st7789屏幕-硬件选择及连接(1)

目录 1.整体介绍 2. 硬件选择 2.1 mbed L432KC 2.2 ST7789 240*240 1.3寸 3. mbed与st7789的硬件连接 4. 总结 1.整体介绍 我们在使用单片机做一些项目的时候,交互性是最重要的因素。那么对于使用者而言,交互最直接的体现无非就是视觉感知,那么我们希望将项目通过视觉…

SpringBoot集成Jasypt对数据库连接密码进行加密、解密

引入依赖 <!--配置密码加密--><dependency><groupId>com.github.ulisesbocchio</groupId><artifactId>jasypt-spring-boot-starter</artifactId><version>3.0.3</version></dependency><plugin><groupId>c…

分类器引导的条件生成模型

分类器引导的条件生成模型 分类器引导的条件生成模型1. **基本概念**2. **核心思想**3. **实现步骤&#xff08;以扩散模型为例&#xff09;**4. **优点**5. **挑战与注意事项**6. **应用场景**7. **数学推导**总结 分类器引导的条件生成模型 分类器引导的条件生成模型是一种通…

WPF中的ObjectDataProvider:用于数据绑定的数据源之一

ObjectDataProvider是WPF(Windows Presentation Foundation)中一种强大而灵活的数据绑定源&#xff0c;它允许我们将对象实例、方法结果甚至是构造函数的返回值用作数据源。通过本文&#xff0c;我将深入探讨ObjectDataProvider的工作原理、使用场景以及如何在实际应用中发挥其…

lasticsearch 报错 Document contains at least one immense term 的解决方案

一、问题背景 在使用 Elasticsearch 存储较大字段数据时&#xff0c;出现如下异常&#xff1a; ElasticsearchStatusException: Elasticsearch exception [typeillegal_argument_exception, reasonDocument contains at least one immense term in field"fieldZgbpka"…

[目标检测] YOLO系列算法讲解

前言 目标检测就是做到给模型输入一张图片或者视频&#xff0c;模型可以迅速判断出视频和图片里面感兴趣的目标所有的位置和它 的类别&#xff0c;而当前最热门的目标检测的模型也就是YOLO系列了。 YOLO系列的模型的提出&#xff0c;是为了解决当时目标检测的模型帧率太低而提…

服务器操作系统时间同步失败的原因及修复

服务器操作系统时间同步失败可能导致日志记录不准确、安全证书失效等问题。以下是常见原因及对应的修复方法&#xff1a; ### 一、时间同步失败的常见原因 1. **网络连接问题** - NTP服务器无法访问&#xff08;防火墙阻止、网络中断&#xff09; - DNS解析失败或网…

Cribl 中function 使用过滤的特殊case:Parser + rename

Cribl 利用function 对parser 进行特殊过滤处理: Parser Function – Fields Filter Expression​ When you use the Stream Parser Functions Reserialize option, there is a special option that becomes available, called the Fields Filter Expression. This is basica…

inverse-design-of-grating-coupler-3d

一、设计和优化3D光栅耦合器 1.1 代码讲解 通过预定义的环形间距参数(distances数组),在FDTD中生成椭圆光栅结构,并通过用户交互确认几何正确性后,可进一步执行参数扫描优化。 # os:用于操作系统相关功能(如文件路径操作) import os import sys# lumapi:Lumerical 的…