Tip of the Week #65: Putting Things in their Place

2023-11-17

Tip of the Week #65: Putting Things in their Place

Originally posted as totw/65 on 2013-12-12
By Hyrum Wright (hyrum@hyrumwright.org)
“Let me ’splain. No, there is too much. Let me sum up.” –Inigo Montoya

C++11中添加了一种新方式往标准容器中插入元素,那就是emplace()系列方法了。这些方法会直接在容器中创建对象,避免创建临时对象,然后通过拷贝或者移动对象到容器中。这对于几乎所有的对象来说避免了拷贝,更加高效。尤其是对于往标准容器中存储只能移动的对象(例如std::unique_ptr)就更为方便了。

The Old Way and the New Way

让我们通过使用vector来存储的一个简单的例子来对比下两种方式。第一个例子是C++11之前的编码风格:

class Foo {
 public:
  Foo(int x, int y);};

void addFoo() {
  std::vector<Foo> v1;
  v1.push_back(Foo(1, 2));
}

通过使用老的push_back方法,会导致Foo对象被构造两次,一次是临时构造一个Foo对象,然后将临时对象进行移动构造,放到容器中。

我们可以使用C++11引入的emplace_back(),这种方式只会引入一个对象的构造,是直接在vector容器元素所在内存上构造。正是由于emplace系列函数将其参数直接转发给底层对象的构造函数,因此我们可以直接提供构造函数参数,从而无需创建临时的Foo对象。

void addBetterFoo() {
  std::vector<Foo> v2;
  v2.emplace_back(1, 2);
}

Using Emplace Methods for Move-Only Operations

到目前为止,我们已经研究过emplace方法可以提高性能的情况,此外它可以让之前不能工作的代码可以正常工作,例如容器中的类型是只能被移动的类型像std::unique_ptr。考虑下面这段代码:

std::vector<std::unique_ptr<Foo>> v1;

如何才能向这个容器中插入一个元素呢? 一种方式就是通过push_back直接在参数中构造对象:

v1.push_back(std::unique_ptr<Foo>(new Foo(1, 2)));

这种语法有效,但可能有点笨拙。不幸的是,解决这种混乱的传统方式充满了复杂性:

Foo *f2 = new Foo(1, 2);
v1.push_back(std::unique_ptr<Foo>(f2));

上面这段代码可以编译,但是它使得在被插入前,指针的所有权变的不清晰。甚至更糟糕的是,vector拥有了该对象,但是f2仍然有效,并且有可能在此后被删除。对于不知情的读者来说,这种所有权模式可能会令人困惑,特别是如果构造和插入不是如上所述的顺序事件。

其他的解决方案甚至都无法编译,因为unique_ptr是不能被拷贝的:

std::unique_ptr<Foo> f(new Foo(1, 2));
v1.push_back(f);             // Does not compile!
v1.push_back(new Foo(1, 2)); // Does not compile!

使用emplace方法会使得对象的创建更为直观,如果你需要把unique_ptr放到vector容器中,可以像下面这样通过std::move来完成:

std::unique_ptr<Foo> f(new Foo(1, 2));
v1.emplace_back(new Foo(1, 2));
v1.push_back(std::move(f));

通过把emplace和标准的迭代器结合,可以将对象插入到vector容器中的任何位置:

v1.emplace(v1.begin(), new Foo(1, 2));

实际上,我们不希望看到上述构造unique_ptr的这些方法,而是希望通过std::make_unique(C++14),或者是absl::make_unique(C++11)。

Conclusion

本文使用vector来作为example中的标准容器,实际上emplace同样也适用于maplist以及其它的STL容器。当unique_ptremplace结合,使得在堆上分配的对象其所有权的语义更加清晰。希望通过本文能让您感受到新的容器方法的强大功能,以及满足在您自己的代码中适当使用它们的愿望。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Tip of the Week #65: Putting Things in their Place 的相关文章

随机推荐

  • 微前端--qiankun原理概述

    demo放最后了 一 微前端 一 微前端概述 微前端概念是从微服务概念扩展而来的 摒弃大型单体方式 将前端整体分解为小而简单的块 这些块可以独立开发 测试和部署 同时仍然聚合为一个产品出现在客户面前 可以理解微前端是一种将多个可独立交付的小
  • Android 热补丁动态修复框架小结

    转载 http blog csdn net xdgaozhan article details 51848570 一 概述 最新github上开源了很多热补丁动态修复框架 大致有 https github com dodola HotFix
  • Python与OpenCV(三)——基于光流法的运动目标检测程序分析

    光流的概念是指在连续的两帧图像当中 由于图像中的物体移动或者摄像头的移动而使得图像中的目标形成的矢量运动轨迹叫做光流 本质上光流是个向量场 表示了一个像素点从第一帧过渡到第二帧的运动过程 体现该像素点在成像平面上的瞬时速度 而当我们对图像当
  • oracle 游标 上限,ORA-01000: 超出打开游标的最大数

    语言 java 数据库 oracle 开发中通过jdbc做批量删除对象时 出现了如下异常 java sql SQLException ORA 01000 超出打开游标的最大数 at oracle jdbc driver T4CTTIoer
  • UE5_创建C++项目报错

    UE官方VS安装推荐 https docs unrealengine com 4 26 en US ProductionPipelines DevelopmentSetup VisualStudioSetup UE5报错 A fatal e
  • 下拉框怎么用ajax实现添加功能,ajax实现动态下拉框示例

    许多页面上都涉及有下拉框 即select标签 对于简单的下拉框 被选择的数据是不需要改变的 我们可以用写死 这样下拉框的数据永远都是那几条 示例 信息一 信息二 信息三 信息四 但是有些项目或者工程是需要将数据库中的数据呈现出来并提供选择的
  • CH3-栈和队列

    文章目录 3 1栈和队列的定义和特点 栈的应用 队列的应用 3 1 1栈的定义和特点 3 1 2队列的定义和特点 3 2案例引入 案例3 1 进制转换 案例3 2 括号匹配的检验 案例3 3 表达式求值 案例3 4 舞伴问题 3 3栈的表示
  • 网络传输方式

    1 单播 1 1 定义 单播是指一种向单个目标地址传送数据的方式 即单独的一对一通讯方式 1 2 可使用协议 UDP TCP等协议 1 3 常见的场景 发送电子邮件 传输文件 2 广播 2 1 定义 一种向本地网络中所有设备发送数据的方式
  • FISCO BCOS 三、多群组部署以及新节点加入群组

    本章主要以星形组网和并行多组组网拓扑为例 指导您了解如下内容 了解如何使用build chain sh创建多群组区块链安装包 了解build chain sh创建的多群组区块链安装包目录组织形式 学习如何启动该区块链节点 并通过日志查看各群
  • 正确加载 Javascript 和 CSS 到 WordPress

    原文 http technerdia com 1789 include jquery css html 正确加载 jQuery Javascript 和 CSS 到你的WordPress网站也许是一件比较痛苦的事情 本文将讲解如何使用Wor
  • 使用python处理selenium中的获取元素属性

    获取我的订单元素class属性值 get class name driver find element by link text 我的订单 get attribute class 判断class属性值是否为active self asser
  • 深度学习半自动化视频标注工具——VATIC使用教程

    Vatic简介 Vatic是一个带有目标跟踪的半自动化视频标注工具 适合目标检测任务的标注工作 输入一段视频 支持自动抽取成粒度合适的标注任务并在流程上支持接入亚马逊的众包平台Mechanical Turk 当然也可以自己在本地标注 最大的
  • 使用markdown写大论文

    目的 用自己中意的 Markdown 编辑器来写论文初稿 使用 Zotero 来管理大量参考文献 然后论文转换成 Office Word 文档让老师们查看 当 Markdown 内容并转换成 Word 格式后 所有引用都需要被 Zotero
  • 【BraTS】Brain Tumor Segmentation 脑部肿瘤分割3--构建数据流

    往期回顾 BraTS Brain Tumor Segmentation 脑部肿瘤分割1 数据篇 BraTS Brain Tumor Segmentation 脑部肿瘤分割2 UNet的复现 在上一篇网络复现中提到 输入图像变成 4 155
  • OSG学习:纹理映射(四)——三维纹理映射

    以下内容来自 1 OpenSceneGraph三维渲染引擎编程指南 肖鹏 刘更代 徐明亮 清华大学出版社 2 OpenSceneGraph三维渲染引擎设计与实践 王锐 钱学雷 清华大学出版社 3 自己的总结 下载完整工程OSG 12 Tex
  • 基于区块链的分布式存储系统开发论文研究

    基于区块链的分布式存储系统开发论文研究 一 论文一 基于区块链的应用系统开发方法研究 蔡维德 论文引用 1 蔡维德 郁莲 王荣 刘娜 邓恩艳 基于区块链的应用系统开发方法研究 J 软件学报 2017 28 06 1474 1487 1 区块
  • 数据结构之二叉查找树(Binary Search Tree)和红黑树(Red Black Tree)

    感兴趣的话大家可以关注一下公众号 猿人刘先生 欢迎大家一起学习 一起进步 一起来交流吧 二叉查找树 Binary Search Tree 二叉查找树又可以称之为 二叉搜索树 二叉排序树 它或者是一棵空树 或者是具有下列性质的二叉树 若它的左
  • jsoup的Elements类

    随时随地阅读更多技术实战干货 获取项目源码 学习资料 请关注源代码社区公众号 ydmsq666 一 简介 该类是位于select包下 直接继承自Object 所有实现的接口有Cloneable Iterable
  • Qt限制文本框输入的方法

    在做界面编程的时候 对文本框的处理往往是个很头疼的事情 一是焦点进入文本框时 从人性化考虑 应选择文本框中文本 方便输入 二是 限制文本框的输入 只允许输入有效的文本 如果不这样做的话 那么就需要在程序中滤去非法输入 在这里介绍一种解决上述
  • Tip of the Week #65: Putting Things in their Place

    Tip of the Week 65 Putting Things in their Place Originally posted as totw 65 on 2013 12 12 By Hyrum Wright hyrum hyrumw