[翻译] Effective C++, 3rd Edition, Item 5: 了解 C++ 为你偷偷地加上和调用了什么函数

不用FFmpeg!纯前端实现RTSP直播的3种现代方案对比(WebSocket/Wasm/WebCodecs) 本文深入探讨了纯前端实现RTSP直播的三种现代技术方案:WebSocket代理转发、Wasm解码和WebCodecs硬解。通过详细的架构设计、性能实测数据和兼容性分析,帮助开发者在安防监控、智慧城市等场景中选择最佳方案,实现低延迟、高效率的视频流处理。 阅读详情

Item 5: 了解 C++ 为你偷偷地加上和调用了什么函数

作者:Scott Meyers

译者:fatalerror99 (iTePub's Nirvana)

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

一个 empty class(空类)什么时候将不再是 empty class(空类)?答案是当 C++ 搞定了它。如果你自己不声明一个 copy constructor(拷贝构造函数),一个 copy assignment operator(拷贝赋值运算符)和一个 destructor(析构函数),编译器就会为这些东西声明一个它自己的版本。此外,如果你自己根本没有声明 constructor(构造函数),编译器就会为你声明一个 default constructor(缺省构造函数)。所有这些函数都被声明为 public 和 inline(参见 Item 30)。作为结果,如果你写

class Empty{};

在本质上和你这样写是一样的:

class Empty {

public:

  Empty() { ... }                            // default constructor

  Empty(const Empty& rhs) { ... }            // copy constructor

  ~Empty() { ... }                           // destructor — see below
                                             // for whether it's virtual

  Empty& operator=(const Empty& rhs) { ... } // copy assignment operator

};

这些函数只有在它们被需要的时候才会生成,但是并不需要做太多的事情,就会用到它们。下面的代码会促使每一个函数生成:

Empty e1;                               // default constructor;
                                        // destructor

Empty e2(e1);                           // copy constructor

e2 = e1;                                // copy assignment operator

假设编译器为你写了这些函数,那么它们做些什么呢?default constructor(缺省构造函数)和 destructor(析构函数)主要是给编译器一个地方放置 "behind the scenes" code(“幕后”代码)的,诸如 base classes(基类)和 non-static data members(非静态数据成员)的 constructors(构造函数)和 destructor(析构函数)的调用。注意,生成的 destructor(析构函数)是 non-virtual(非虚拟)的(参见 Item 7),除非它所在的 class(类)是从一个 base class(基类)继承而来,而 base class(基类)自己声明了一个 virtual destructor(虚拟析构函数)(这种情况下,函数的 virtualness(虚拟性)来自 base class(基类))。

对于 copy constructor(拷贝构造函数)和 copy assignment operator(拷贝赋值运算符),compiler-generated versions(编译器生成版本)只是简单地从 source object(源对象)拷贝每一个 non-static data member(非静态数据成员)到 target object(目标对象)。例如,考虑一个 NamedObject template(模板),它允许你将名字和类型为 T 的 objects(对象)联系起来的:

template<typename T>
class NamedObject {
public:
  NamedObject(const char *name, const T& value);
  NamedObject(const std::string& name, const T& value);

  ...

private:
  std::string nameValue;
  T objectValue;
};

因为 NamedObject 中声明了一个 constructors(构造函数),编译器就不会再生成一个 default constructor(缺省构造函数)。这一点很重要,它意味着如果你小心地设计一个 class(类),使它需要 constructor arguments(构造函数参数),你就不必顾虑编译器会不顾你的决定,轻率地增加一个不需要参数的 constructors(构造函数)。

NamedObject 既没有声明 copy constructor(拷贝构造函数)也没有声明 copy assignment operator(拷贝赋值运算符),所以编译器将生成这些函数(如果需要它们的话)。看,这就是 copy constructor(拷贝构造函数)的用法:

NamedObject<int> no1("Smallest Prime Number", 2);

NamedObject<int> no2(no1);                 // calls copy constructor

编译器生成的 copy constructor(拷贝构造函数)一定会用 no1.nameValue 和 no1.objectValue 分别初始化 no2.nameValue 和 no2.objectValue。nameValue 的类型是 string,标准 string 类型有一个 copy constructor(拷贝构造函数),所以将通过以 no1.nameValue 作为参数调用 string 的 copy constructor(拷贝构造函数)初始化 no2.nameValue。而另一方面,NamedObject<int>::objectValue 的类型是 int(因为在这个 template instantiation(模板实例化)中 T 是 int),而 int 是 built-in type(内建类型),所以将通过拷贝 no1.objectValue 的每一个二进制位初始化 no2.objectValue。

编译器为 NamedObject<int> 生成的 copy assignment operator(拷贝赋值运算符)本质上也会有同样的行为,但是,通常情况下,只有在结果代码合法而且有一个合理的可理解的巧合时,compiler-generated(编译器生成)的 copy assignment operator(拷贝赋值运算符)才会有我所描述的行为方式。如果这两项检测中的任一项失败了,编译器将拒绝为你的 class(类)生成一个 operator=。

例如,假设 NamedObject 如下定义,nameValue 是一个 reference to a string(引向一个字符串的引用),而 objectValue 是一个 const T:

template<class T>
class NamedObject {
public:
  // this ctor no longer takes a const name, because nameValue
  // is now a reference-to-non-const string. The char* constructor
  // is gone, because we must have a string to refer to.
  NamedObject(std::string& name, const T& value);

  ...                               // as above, assume no
                                    // operator= is declared

private:
  std::string& nameValue;           // this is now a reference
  const T objectValue;              // this is now const
};

现在,考虑这里会发生什么:

std::string newDog("Persephone");

std::string oldDog("Satch");

NamedObject<int> p(newDog, 2);               // when I originally wrote this, our
                                             // dog Persephone was about to
                                             // have her second birthday
NamedObject<int> s(oldDog, 36);              // the family dog Satch (from my
                                             // childhood) would be 36 if she
                                             // were still alive

p = s;                                       // what should happen to
                                             // the data members in p?

assignment(赋值)之前,p.nameValue 和 s.nameValue 都引向 string objects(对象),虽然并非同一个。那个 assignment(赋值)对 p.nameValue 产生了什么影响呢?assignment(赋值)之后,p.nameValue 所引向的 string 是否就是 s.nameValue 所引向的那一个呢,也就是说,reference(引用)本身被改变了?如果是这样,就违反了常规,因为 C++ 并没有提供使一个 reference(引用)引向另一个 objects(对象)的方法。换一种思路,是不是 p.nameValue 所引向的那个 string objects(对象)被改变了,从而影响了其他 objects(对象)—— pointers(指针)或 references(引用)持续指向的那个 string,也就是,赋值中并没有直接涉及到的对象?这是 compiler-generated(编译器生成)的 copy assignment operator(拷贝赋值运算符)应该做的事情吗?

面对这个难题,C++ 拒绝编译代码。如果你希望一个包含 reference member(引用成员)的 class(类)支持 assignment(赋值),你必须自己定义 copy assignment operator(拷贝赋值运算符)。对于含有 const members(const 成员)的 classes(类),编译器会有类似的行为(就像上面那个改变后的 class(类)中的 objectValue)。改变 const members(const 成员)是不合法的,所以编译器隐式生成的 assignment function(赋值函数)无法确定该如何对待它们。最后,如果 base classes(基类)将 copy assignment operator(拷贝赋值运算符)声明为 private,编译器拒绝为从它继承的 derived classes(派生类)生成 implicit copy assignment operators(隐式拷贝赋值运算符)。毕竟,编译器为派生类生成的 copy assignment operator(拷贝赋值运算符)也要处理其 base class parts(基类构件)(参见 Item 12),但如果这样做,它们当然无法调用那些 derived classes(派生类)无权调用的 member functions(成员函数)。

Things to Remember

  • 编译器可以隐式生成一个 class(类)的 default constructor(缺省构造函数),copy constructor(拷贝构造函数),copy assignment operator(拷贝赋值运算符)和 destructor(析构函数)。
ABAQUS二次开发中创建SET 在ABAQUS中创建加载、边界条件时,需要使用set,创建set时需要使用对象集合对象中的Set函数,这个函数需要提供加入对象集合的列表,但这个对象列表好像并不能自行创建,只能通过ABAQUS各类对象集合中的findAt、getSequenceFromMask、getByBoundingSphere、getByBoundingCylinder或getByBoundingSphere函数得到,但这几个函数在直接使用PYTHON编程时都不太好用。这个函数返回一个字典,如下所示。 阅读详情

相关推荐

价值投资/指标选股(akshare)

利用akshare的数据源,可以获取所有的股票数据以及公开的财务数据,可以进行条件筛选,获取满足条件的股票。 这套模板可以用于价值投资,指标选股。选股周期为日线级别。然后结果可以邮箱发送。 import time import akshare as ak ## A 股上市公司的实时行情数据 stock_zh_a_spot_df = ak.stock_zh_a_spot() #print(stock_zh_a_spot_df) ##取前300测试 ##取前300测试 df_stock =...

qq_26742269的博客 1万+

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

(先进后出)

xys_678的博客 254

联邦学习模型投毒研究进展

在联邦学习中,多个设备(如移动设备、IoT设备等)本地训练模型,然后将更新的模型参数上传到服务器进行聚合。

2401_82375734的博客 1267

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

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

Maxwell_Newton的博客 349

Python 实现生命游戏及进化模拟完整指南

生命模拟是进化计算的一个特定子集,模拟了自然界中所观察到的自然过程,例如粒子或鸟群的聚集方式。生命模拟只是用来探索和优化问题的模拟形式之一,还有很多其他形式的模拟,可以更好地建模各种过程,但它们都源于康威生命游戏 (Conway’s Game of Life)。在本节中,我们将介绍生命模拟的基本概念,并使用 Python 实现康威生命游戏。

盼小辉丶的博客 7万+

第38节:cesium 风场效果(含源码+视频)

cesium 风场效果

qq_29384639的博客 2331

C++移动构造函数详解

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

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

PINN求解PDE

PINN求解Dirichlet泊松方程 泊松方程引入 −Δu=f,x∈Ω=(0,1)2-\Delta u=f,x \in \Omega=(0,1)^2−Δu=f,x∈Ω=(0,1)2 u=g,x∈∂Ωu=g,x \in \partial \Omegau=g,x∈∂Ω import torch import time import numpy as np import matplotlib.pyplot as plt import torch.nn as nn def UU(X, order,prob):

forrestguang的博客 3806

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

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

fpcc的专栏 88

C#实战大华智能安防系统:从SDK封装到视频流与智能报警的全链路落地

本文将介绍C#集成大华SDK开发安防系统的实战经验,重点解决多路视频预览卡顿和报警延迟问题。文章通过三层架构设计(SDK封装层、业务服务层、应用层)实现解耦,详细分析线程安全封装、高效解码显示和智能事件联动等核心技术。针对16路摄像头同时预览时CPU占用率过高的问题,提出使用子码流拉流与异步解码的优化方案,并总结8个常见开发陷阱的解决方案。文中还提供了大华智能安防系统的完整架构图,展示从设备层到应用层的交互流程,特别强调业务服务层中视频流服务和智能报警服务的核心功能设计。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 432

【AIGC】大模型面试高频考点09-大模型Agent框架

聚焦AIGC专业技术分享

一个内容严谨、方向前沿、极具实践价值的AI大模型技术分享站 1967

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

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

2602_95684935的博客 492

网络工程师面试题汇总(二)

网络把主机连接起来,而互连网(internet)是把多种不同的网络连接起来,因此互连网是网络的网络。而互联网(Internet)是全球范围的互连网。因为网络层是整个互联网的核心,因此应当让网络层尽可能简单。网络层向上只提供简单灵活的、无连接的、尽最大努力交互的数据报服务。使用 IP 协议,可以把异构的物理网络连接起来,使得在网络层看起来好像是一个统一的网络。地址解析协议 ARP(Address Resolution Protocol)

悦分享 185

C++ 函数模版

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

2501_94041724的博客 307

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

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

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

Fuyo_0209的博客 450

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

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

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

lwq20051110的博客 251

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

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

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

zhangjw34的专栏 105

【C++ 基础入门】C++继承(下):问题、底层原理与组合

C++继承(菱形继承的问题、虚继承原理、继承与组合、构造顺序)

2601_96587588的博客 802

蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级 备考:莫队算法离线区间查询详解

备赛进行时:第十八届蓝桥杯软件赛报名已于 2026-10-08 10:00 开启、12-18 14:00 截止,省赛定在 2027-04-10(C/C++·Python 程序设计 9:00–13:00);中国电子学会 2026 年 12 月软件编程(C/C++ 一级至十级、Python 一级至六级)考级报名 9/23–12/2 16:00、统考 12-12;全国青少年信息素养大赛 2026—2027 赛季算法应用主题赛也已进入复盘练兵窗口。

IT_Scratch的博客 170

c++ explicit关键字详解

explicit。

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

825 mW 顶上 212 °C:ASM491S 的 105 °C/W、250 mA 短路电流与热关断

25 °C 环境里结温 34.1 °C,125 °C 环境里结温 134.1 °C——后者已经离 150 °C 只有 16 °C 了,但还在范围内。换个角度看同一件事:从 25 °C 和从 125 °C 起算,温升都是 86.6 °C,但一个到 111.6 °C(还在范围内),一个到 211.6 °C(远远超限)。这个算例里 20 °C/W 是我假设的,实际值取决于机壳材料、密封程度、有没有风扇,跨度可以从 5 °C/W 到 50 °C/W 以上。外面 50 °C 的机箱,盒内就是 63.9 °C。

ANSILIC的博客 393

《C++ 项目:手写大模型接入 SDK》Gemini接口设计(上):初始化、全量响应实现和测试

本文系统完成了Gemini模型通过OpenAI兼容API的接入开发,基于Apifox验证接口规范,设计并实现GeminiProvider类,涵盖初始化、状态检测、全量响应等核心功能。重点处理了代理配置强制校验、Bearer鉴权、JSON序列化与响应解析等工程细节,并通过GTest与CMake完成单元测试,验证链路可用性。项目遵循策略模式,保持与DeepSeek、ChatGPT等模型的统一抽象接口,显著提升SDK可扩展性。

2501_91275995的博客 398

【容斥原理计数】题解:P9489 ZHY的表示法_容斥原理_计数问题_前缀和问题转化_算法竞赛C++

给定 $ n $ 个正整数,求区间 $[l,r]$ 中有多少正整数 $ x $ 可表示为 $ \sum \lfloor \frac{y}{x_i} \rfloor $。通过二分确定最大 $ y $,转化为求 $ 1 \sim H $ 中是某些 $ x_i $ 倍数的数的个数,利用容斥原理与 DFS 枚举子集计算,结合 LCM 预判剪枝及去重优化,时间复杂度 $ O(2^n \log V) $,可高效处理 $ r \le 10^9 $ 的数据。

YLCHUP的博客 106

头歌 数据结构——C&C++线性表实训

本系列任务围绕线性表的链式实现,依次完成顺序构建、逆序构建、排序插入、查找、删除、求长度及栈、队列、集合等应用。通过动态内存分配与指针操作,掌握单链表的基本操作与实际应用,涵盖插入、删除、遍历、搜索等核心功能,最终实现数据结构在典型场景中的灵活运用。

一名敲代码的苦13程序员 244

字母移动游戏题解:贪心求最长可保留连续子串(附 C 实现)

本题核心思想是:最少移动步数 = 总长度 - 可保留的最长连续子串长度。未移动字母在T中必须为连续子串,在S中需保持相对顺序(即子序列)。通过枚举T的所有连续子串起点,贪心匹配S中的对应字符,求出最长可保留长度L,答案即为n−L。时间复杂度O(n²),空间复杂度O(n),适用于n≤1000。

冻柠茶飞冰走茶 592

C++ 标准库算法全景指南

本文系统梳理C++标准库<algorithm>与<numeric>中100+算法,按功能分为非修改、修改、排序、二分查找、归并、堆、极值、字典序、排列及数值操作十大类,涵盖典型用法与时间复杂度。结合C++20范围(ranges)与投影特性,实现更简洁高效的代码。

sss123ddd的博客 402
上一篇: [翻译] Effective C++, 3rd Edition, Item 4: 确保 objects(对象)在使用前被初始化
下一篇: [翻译] Effective C++, 3rd Edition, Item 6: 如果你不想使用 compiler-generated functions(编译器生成函数),就明确拒绝
fatalerror99
博客等级 码龄24年 166粉丝 20原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值