[翻译] Effective C++, 3rd Edition, Item 25: 考虑支持一个 non-throwing swap(不抛异常的 swap)(上)

Qlib+backtrader:2014.1.1-2023.9.20最新回测结果,可以实盘吗? 今年以来,在研究了qlib和backtrader的基础上,把二者结合起来进行了一个策略研究。简单说就是用qlib在200只股票的股票池中进行滚动训练与预测(walk forward),总体数据范围是2005到2023年,以20日间隔滚动训练和预测,最终得到2014.1.1-2023.9.20共10年测试期的收益率预测结果。将预测结果代入backtrader进行回测,得到如下回测结果。 阅读详情

Item 25: 考虑支持一个 non-throwing swap(不抛异常的 swap)

作者:Scott Meyers

译者:fatalerror99 (iTePub's Nirvana)

发布:http://blog.youkuaiyun.com/fatalerror99/

swap 是一个有趣的函数。最早作为 STL 的构件被引入,后来它成为 exception-safe programming(异常安全编程)的支柱(参见 Item 29)和压制自赋值可能性的通用机制(参见 Item 11)。因为 swap 太有用了,所以适当地实现它非常重要,但是伴随它的不同寻常的重要性而来的,是一系列不同寻常的复杂性。在本 Item 中,我们就来研究一下这些复杂性究竟是什么样的以及如何对付它们。

swap(交换)两个 objects 的值就是互相把自己的值送给对方。缺省情况下,经由标准的 swap 算法来实现交换是非常成熟的技术。典型的实现完全符合你的预期:

namespace std {

  template<typename T>          // typical implementation of std::swap;
  void swap(T& a, T& b)         // swaps a's and b's values
  {
    T temp(a);
    a = b;
    b = temp;
  }
}

只要你的类型支持拷贝(经由 copy constructor(拷贝构造函数)和 copy assignment operator(拷贝赋值运算符)),缺省的 swap 实现就能交换你的类型的 objects,而不需要你做任何特别的支持工作。

然而,缺省的 swap 实现可能不那么酷。它涉及三个 objects 的拷贝:从 a 到 temp,从 b 到 a,以及从 temp 到 b。对一些类型来说,这些副本全是不必要的。对于这样的类型,缺省的 swap 就好像让你坐着快车驶入小巷。

这样的类型中最重要的就是那些主要由一个指针组成的类型,那个指针指向包含真正数据的另一种类型。这种设计方法的一种常见的表现形式是 "pimpl idiom"("pointer to implementation" ——参见 Item 31)。一个使用了这种设计的 Widget class 可能就像这样:

class WidgetImpl {                          // class for Widget data;
public:                                     // details are unimportant
  ...

private:
  int a, b, c;                              // possibly lots of data —
  std::vector<double> v;                    // expensive to copy!
  ...
};

class Widget {                              // class using the pimpl idiom
public:
  Widget(const Widget& rhs);

  Widget& operator=(const Widget& rhs)      // to copy a Widget, copy its
  {                                         // WidgetImpl object. For
   ...                                      // details on implementing
   *pImpl = *(rhs.pImpl);                   // operator= in general,
   ...                                      // see Items 10, 11, and 12.
  }
  ...

private:
  WidgetImpl *pImpl;                         // ptr to object with this
};                                           // Widget's data

为了交换这两个 Widget objects 的值,我们实际要做的全部就是交换它们的 pImpl pointers(指针),但是缺省的 swap 算法没有办法知道这些。它不仅要拷贝三个 Widgets,而且还有三个 WidgetImpl objects,效率太低了。一点都不酷。

我们想要做的就是告诉 std::swap 当交换 Widgets 的是时候,执行交换的方法就是 swap 它们内部的 pImpl pointers。这种方法的正规说法是:specialize std::swap for Widget(针对 Widget 特化 std::swap)。下面是一个基本的想法,虽然在这种形式下它还不能通过编译:

namespace std {

  template<>                            // this is a specialized version
  void swap<Widget>(Widget& a,          // of std::swap for when T is
                    Widget& b)          // Widget; this won't compile
  {
    swap(a.pImpl, b.pImpl);             // to swap Widgets, just swap
  }                                     // their pImpl pointers
}

这个函数开头的 "template<>" 表明这是一个针对 std::swap 的 total template specialization(完全模板特化)(某些书中称为 "full template specialization" 或 "complete template specialization" ——译者注),函数名后面的 "<Widget>" 表明这个 specialization(特化)是在 T 为 Widget 时发生的。换句话说,当通用的 swap template(模板)用于 Widgets 时,就应该使用这个实现。通常,我们不被允许改变 std namespace 中的内容的,但我们被允许为我们自己创建的类型(比如 Widget)完全地特化标准模板(比如 swap)。这就是我们现在在这里做的事情。

可是,就像我说的,这个函数还不能编译。那是因为它试图访问 a 和 b 内部的 pImpl pointers(指针),而它们是 private(私有)的。我们可以将我们的 specialization(特化)声明为一个 friend(友元),但是惯例是不同的:它让 Widget 声明一个名为 swap 的 public member function(公有成员函数)去做实际的交换,然后特化 std::swap 去调用那个 member function(成员函数):

class Widget {                     // same as above, except for the
public:                            // addition of the swap mem func
  ...
  void swap(Widget& other)
  {
    using std::swap;               // the need for this declaration
                                   // is explained later in this Item

    swap(pImpl, other.pImpl);      // to swap Widgets, swap their
  }                                // pImpl pointers

  ...
};

namespace std {

  template<>                       // revised specialization of
  void swap<Widget>(Widget& a,     // std::swap
                    Widget& b)
  {
    a.swap(b);                     // to swap Widgets, call their
  }                                // swap member function
}

这个不仅能够编译,而且和 STL containers(容器)保持一致,所有 STL containers(容器)都既提供了 public swap member functions(公有 swap 成员函数),又提供调用这些 member functions(成员函数)的 std::swap 的 specializations(特化)。

可是,假设 Widget 和 WidgetImpl 是 class templates(类模板),而不是 classes(类),或许因此我们可以参数化存储在 WidgetImpl 中的数据的类型:

template<typename T>
class WidgetImpl { ... };

template<typename T>
class Widget { ... };

在 Widget 中加入一个 swap member function(成员函数)(如果我们需要,在 WidgetImpl 中也加一个)就像以前一样容易,但我们特化 std::swap 时会遇到麻烦。这就是我们要写的代码:

namespace std {
  template<typename T>
  void swap<Widget<T> >(Widget<T>& a,      // error! illegal code!
                        Widget<T>& b)
  { a.swap(b); }
}

这看上去非常合理,但它是非法的。我们试图 partially specialize(部分特化)一个 function template(函数模板)(std::swap),但是尽管 C++ 允许 class templates(类模板)的 partial specialization(部分特化),但不允许 function templates(函数模板)这样做。这样的代码不能编译(尽管一些编译器错误地接受了它)。

当我们想要 "partially specialize"(“部分地特化”)一个 function templates(函数模板)时,通常做法是简单地增加一个 overload(重载)。看起来就像这样:

namespace std {

  template<typename T>             // an overloading of std::swap
  void swap(Widget<T>& a,          // (note the lack of "<...>" after
            Widget<T>& b)          // "swap"), but see below for
  { a.swap(b); }                   // why this isn't valid code
}

通常,重载 function templates(函数模板)确实很不错,但是 std 是一个特殊的 namespace,而且管理它的规则也是特殊的。它认可完全地特化 std 中的 templates(模板),但它不认可在 std 中增加 new templates(新的模板)(或 classes,或函数,或其它任何东西)。std 的内容由 C++ 标准化委员会单独决定,并禁止我们对他们做出的决定进行增加。而且,禁止的方式使你无计可施。打破这条禁令的程序差不多的确可以编译和运行,但它们的行为是未定义的。如果你希望你的软件有可预期的行为,你就不应该向 std 中加入新的东西。

(本篇未完,点击此处,接下篇)

Vcenter安全加固-防火墙-只允许特定的IP地址访问Vcenter 3、此时除了被允许的IP地址可以访问之外,其余地址均被防火墙阻挡。2、再进行0.0.0.0/0匹配所有其他IP地址进行拒绝访问。1、只需要关注接受和拒绝即可。2、其余选择不是这个场景使用的。1.只允许特定的IP地址访问Vcenter。1、登录Vcenter管理界面。2、点击防火墙-添加。 阅读详情

相关推荐

从Arduino IDE到Atmel Studio:ATmega328P开发的进阶之路

本文探讨了从Arduino IDE转向Atmel Studio进行ATmega328P开发的进阶路径。通过对比两者差异,详细介绍了Atmel Studio的环境配置、寄存器操作思维、烧录方法及高级调试功能,帮助开发者突破Arduino的封装限制,实现对单片机底层硬件的精细控制与性能优化,提升嵌入式开发的专业能力。

weixin_29193259的博客 126

Effective C++之条款25:考虑写出一个不抛出异常的swap函数

声明: 文中内容收集整理自《Effective C++(中文版)第三版》,版权归原书所有。 本内容在作者现有能力的基础上有所删减,另加入部分作者自己的理解,有纰漏之处敬请指正。 条款25:考虑写出一个不抛出异常的swap函数 Consider support for a non-throwing swap. swap是个有趣的函数。原本它只是STL的一部分,而后成为异常安全性编程(exce...

HakunaMatata的博客 275

Cesium实战:全球海洋动态水面与自定义区域波浪效果实现

本文详细介绍了在Cesium中实现全球海洋动态水面与自定义区域波浪效果的实战方法。通过解析核心概念Primitive与Geometry,并深入讲解Water材质的关键参数调节,指导开发者快速创建逼真的动态海洋。文章重点阐述了如何利用多边形坐标定义不规则图形区域,实现精准的局部水域波浪效果,并提供了性能优化与视觉提升的实用技巧。

weixin_29256771的博客 501

Effective C++ 条款25_考虑写出一个不抛异常的 swap 函数_不止于此

Consider support for a non-throwing swap swap 是个有趣的函数。原本它只是 STL 的一部分,而后成为异常安全性编程的脊柱,以及用来处理自我赋值可能性(见条款 11)的一个常见机制。由于 swap 如此有用,适当的实现很重要。然而在非凡的重要性之外它也带来了非凡的复杂度。本条款探讨这些复杂度及因应之道。 所谓 swap (置换)两对象值,意思是将两对象的值彼此赋予对方。缺省情况下 swap 动作可由标准程序库提供的 swap 算法完成: namespace std

嘟嘟的博客 282

PhoenixSuit全志刷机实战:从驱动安装到固件烧录的完整避坑指南

本文提供全志芯片设备使用PhoenixSuit进行线刷的完整实战指南。详细介绍了从驱动安装、双公头USB线连接、强制刷机模式进入,到固件烧录全过程的核心步骤与常见错误排查。重点解析了如何避免驱动安装失败、正确触发刷机模式以及应对烧录卡顿等关键问题,帮助用户顺利完成刷机或救砖操作。

algae的博客 1694

从0开始部署基础的AlwaysOn

在这个快餐文化盛行的时代,应该没多少人真的会沉下心来看理论和具体步骤,加上我自己也需要一篇可以扩展的快速搭建环境的指引,所以特别写了这篇文章。 我们在这里要做的事情有以下几个:安装环境。包括虚拟机和网络配置等。安装Windows域、配置必要的账号密码及功能。搭建域环境并进行配置。安装配置Windows Server Failover Cluster(WSFC)。安装SQL Server。配置Alw

MVP黄钊吉(發糞塗牆) 7569

不抛出异常的swap

#include using namespace std; /* 1.提供一个public swap成员函数,让它 高效地置换你的 类型 的 两个成员对象 (绝不会抛出异常) 2.在class 或 template 所在 命名空间 内 提供 一个 non-member swap(非成员 函数 的 swap), 并 令它 调用swap 成员函数 3.为正在 编写的 类 class (非 class

INGNIGHT的专栏 717

STM32 CAN发送丢包?3个邮箱轮询法实测有效(附代码)

本文深入分析了STM32 CAN总线发送丢包的根本原因,指出其内置CAN控制器的三个发送邮箱是硬件瓶颈。针对高负载场景,提供了实测有效的优化方案,重点介绍了非阻塞的邮箱状态轮询法,该方法通过主动轮询三个邮箱的空闲状态,充分利用硬件资源,显著提升发送稳定性并避免任务阻塞。文中附有可直接使用的示例代码。

weixin_29189381的博客 195

考虑支持一个 non-throwing swap(不抛异常的 swap)

SWAP 是一个有趣的函数。最早作为 STL 的构件被引入,后来它成为 exception-safe programming(异常安全编程)的支柱和压制自赋值可能性的通用机制。因为 swap 太有用,所以适当地实现它非常重要,但伴随它的不同寻常的重要性而来的,是一系列不同寻常的复杂性。 swap(交换)两个 objects 的值就是互相把自己的值送给对方。缺省情况下,经由标准的 swa

armman的专栏 3118

SSD盘符漂移导致OSD down场景模拟与恢复

运维团队反馈一个问题,现象是:某个OSD对应的cache分区发生了变化,比如原来cache使用的分区是/dev/sde,后来还是这块盘,但分区信息不知何故,变成了/dev/sdf(产品OSD设备并不是根据分区名称来map,而是根据partlabel),最终的现象是这个OSD down了,没法启动.接到这个现象的反馈后,记录一下这个问题在lab的复现方法。

Gavin Blog 942

玩转 InternVL3.5 轻量级实战:从部署到优化的全记录

玩转 InternVL3.5 轻量级实战:从部署到优化的全记录

jacke121的专栏 626

写一个不抛异常的swap函数

Consider support for a non-throwing swap.STL中的swap算法:namespace std{templatevoid swap(T& a,T& b){T temp(a);a=b;b=temp;}} 复制动作无一必要。考虑以指针指向一个对象,内含真正数据。class WidgetImpl{publi

woshipangxiaofeng的专栏 443

22、嵌入式软件随机延迟生成与加密算法防护技术

本文探讨了嵌入式软件中的随机延迟生成方法与块密码软件实现的高阶掩码及洗牌技术。重点介绍了浮动均值延迟生成方法,其在8位AVR平台上的实现效率为Θ(1),显著提升了抗相关功率分析(CPA)攻击的能力,相比传统方法更安全且轻量。同时,分析了高阶掩码与洗牌技术结合的方案,通过理论建模量化其对高级差分功率分析(DPA)攻击的抵抗能力,并以AES为例展示了该方案的应用流程。最后对比了不同防护技术在安全性与开销之间的权衡,为实际应用中选择合适的安全策略提供了依据。未来可进一步优化实现效率并融合多种防护手段以应对复杂安全

fern8的博客 88

[翻译] Effective C++, 3rd Edition, Item 25: 考虑支持一个 non-throwing swap(不抛异常的 swap)(下)

(点击此处,接上篇)那么该怎么做呢?我们依然需要一个方法,既使其他人能调用 swap,又能让我们得到更高效的 template-specific(模板专用)版本。答案很简单。我们依然声明一个 non-member(非成员)swap 来调用 member(成员)swap,只是不再将那个 non-member(非成员)声明为 std::swap 的 specialization(特化)或 over

艺术编程 2793

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

条款25:考虑写出一个不抛异常的swap函数(Consider support for a non-throwing swap)

STL的东西,总是不懂呀!!!! 转载于:https://www.cnblogs.com/chip/p/4811442.html

weixin_30748995的博客 137

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

【C++】异常处理

1、简介  异常处理(exception handling) 机制允许程序中独立开发的部分能够在运行时就出现的问题进行通信兵做出相应的处理。异常使得我们能够将问题的检测与解决过程分类开来。程序的一部分负责检测问题的出现,然后解决该问题的任务传递给程序的另一部分。检测环节无须知道问题处理模块的所有细节,反之亦然。 2、抛出异常  C++语言中,通过 抛出(throwing) 一条表达式来 引发(raised) 一个异常。被抛出的表达式的类型以及当前的调用链共同决定了哪段 处理代码(handler) 将被用来处

明朗晨光的专栏 1229

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

c ++异常处理_C ++中异常处理的7个最佳实践

c ++异常处理 如果您观察学习曲线的初始阶段,那么C ++中的异常处理将是一个没有学到的话题。 在线提供了大量有关C ++中异常处理的教程和示例。 但是很少有人解释您不应该做的事情以及与此相关的复杂性。 因此,在这里,我们将看到一些复杂之处,从何处以及为什么不应该抛出异常,以及Modern C ++中引入的一些新的新功能,以示例进行异常处理。 我不是专家,但这是我从各种来源,课程和行业经验中学...

编程故事的地方 848

深挖C++:类和对象(中)

(先进后出)

xys_678的博客 254

C++移动构造函数详解

移动构造函数是C++11引入的一种特殊构造函数,用于从临时对象(右值)"窃取"资源来初始化新对象,而不是进行昂贵的深拷贝。char* data;public:// 移动构造函数:参数是右值引用 &&// 关键:把源对象的资源置空。

拒绝AI文,努力在AI时代写出感动人心的好文章 394

ThunderKittens 深度解析:一个不基于 MLIR 的 C++ 模板 GPU DSL

Triton 是"让更多人能写 GPU kernel",ThunderKittens 是"让会写的人写得更爽"。前者用 MLIR 换易用性,后者用 C++ 模板换可控性。它们不是替代关系,而是覆盖了 GPU 编程光谱的两端。ThunderKittens 的出现,本质上是对"GPU DSL 必须基于 MLIR"这一默认假设的挑战。编译期类型系统本身就可以是一个强大的 DSL 基础设施,不需要中间 IR,不需要黑盒 pass,也能实现 tile 级抽象和零运行时开销。

Maxwell_Newton的博客 349

跟我学c++中级篇—类型定义的方式

本文系统阐述了编程中类型定义的重要性及c++中的实现方式。重点对比了宏定义、typedef与modern using三种机制,指出using在可读性、灵活性和模板支持上的优势,推荐优先使用。同时提醒开发者注意别名滥用、类型歧义、错误信息冗长等问题,强调统一规范与合理设计。最终结论:在现代c++开发中,应以using为主,兼顾简洁性与可维护性,避免陷入命名混乱与编译困境。

fpcc的专栏 88

【C++——类和对象(上)】筑基篇:以封装奠定面向对象之基

本文系统梳理C++类与对象的核心知识点,涵盖类的定义、访问限定符(public/private)、类作用域、对象实例化及内存布局。重点解析封装思想、this指针机制、空类大小为1字节的原因,以及类与对象在内存中的存储差异。通过对比C语言结构体与C++类,揭示面向对象设计的优势:数据保护、接口统一、命名隔离与代码可维护性提升。内容由浅入深,适合作为学习笔记与复习参考。

2602_95684935的博客 496

C++ 函数模版

模板参数:● template ,T 就是类型占位符,名字可以自定义,习惯用T● 占位符可以在函数返回值、形参、函数内部当作类型使用使用要点模板代码一般写在头文件:编译器需要看到完整模板源码,才能在每个编译单元完成实例化全局函数、类内成员函数都可以写成模板实例化发生在编译阶段,不是运行时隐式实例化:调用时编译器自动推导实参类型,生成对应版本函数。

2501_94041724的博客 307

C++ 运行时多态与虚函数机制全面剖析【面试重点】

构成C++ 运行时多态必须是基类的指针或者引用调用虚函数。被调用的函数必须是虚函数,并且派生类必须对该虚函数完成重写/覆盖(Override)。只有基类的指针或引用才能既指向基类对象,又指向派生类对象(切片机制);而只有完成了虚函数重写,派生类与基类才具备不同的函数行为,达到“指向谁就调用谁”的效果。在类成员函数的前面加上virtual关键字修饰,该成员函数就成为了虚函数。public:// 成员函数前加 virtual 修饰,声明为虚函数。

Fuyo_0209的博客 450

#SQLite 数据库笔记一:(概念 / 终端指令 / SQL 语句 / C 编程 / 回调函数)

数据库 = 数据的仓库,假设数据是海量。能力说明存储数据持久化保存,程序退出数据还在统计数据、分组、排序数据管理增、删、改、查(CRUD)嵌入式设备上也会用数据库(单片机网关、路由器、工业 HMI 都常见),因为 sqlite 体积小、无需服务进程、单文件即可。数据库 = 库 > 表 > 记录(行) > 字段(列)sqlite3 = 开源、C 写的、单文件、免安装、最多 2T 的嵌入式关系型数据库。

lwq20051110的博客 251

1-10 PostgreSQL中多表连接全解:inner/left/right/full/cross join

本文基于 PostgreSQL 15+ 完整拆解 5 种主流连接:内连接、左连接、右连接、全连接、笛卡尔连接。结合可落地的测试数据,演示每种连接的执行逻辑、返回结果,重点剖析 NULL 值对 JOIN 匹配的核心影响,彻底解决多表连接数据丢失、匹配异常、结果错乱的问题。

zhangjw34的专栏 105
上一篇: [翻译] Effective C++, 3rd Edition, Preface(前言)
下一篇: [翻译] Effective C++, 3rd Edition, Item 25: 考虑支持一个 non-throwing swap(不抛异常的 swap)(下)
fatalerror99
博客等级 码龄24年 166粉丝 20原创
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值