类和对象下(内部类,匿名对象,对象拷贝时的编译器优化)
5.内部类•如果一个类定义在另一个类的内部这个内部类就叫做内部类。内部类是一个独立的类跟定义在全局相比他只是受外部类类域限制和访问限定符限制所以外部类定义的对象中不包含内部类。•内部类默认是外部类的友元类。• 内部类本质也是一种封装当A类跟B类紧密关联A类实现出来主要就是给B类使用那么可以考虑把A类设计为B的内部类如果放到private/protected位置那么A类就是B类的专属内部类其他地方都用不了。• 代码示例#include iostream using namespace std; class Outer { public: // 内部类定义在外部类内部 class Inner { public: void show() { cout Inner class method endl; } }; void useInner() { Inner in; in.show(); } }; int main() { Outer::Inner obj; // 通过外部类访问内部类 obj.show(); return 0; }• 内部类默认是外部类的友元类因此内部类可以直接访问外部类的私有成员#include iostream using namespace std; class Outer { private: int value 100; public: class Inner { public: void accessOuter(Outer o) { // 内部类作为友元可直接访问外部类的私有成员 cout Outer private value: o.value endl; } }; }; int main() { Outer o; Outer::Inner in; in.accessOuter(o); return 0; }6.匿名对象• 用类型(实参)定义出来的对象叫做匿名对象匿名对象的特点不用取名字例如A();相比之前我们定义的类型对象名(实参)定义出来的叫有名对象。• 匿名对象生命周期只在当前一行一般临时定义一个对象当前用一下即可就可以定义匿名对象。• 代码示例#include iostream using namespace std; class A { public: A(int x 0) : _x(x) { cout A(int) endl; } ~A() { cout ~A() endl; } void show() const { cout x _x endl; } private: int _x; }; // 匿名对象作为函数参数 void func(const A a) { cout func called endl; } int main() { // 匿名对象A(10) 没有名字生命周期仅限当前这一行 A(10).show(); // 临时调用成员函数行末即析构 func(A(20)); // 匿名对象作为函数实参函数调用结束后析构 cout main continues endl; return 0; }• 上例中A(10)和A(20)都是匿名对象它们没有对象名生命周期只持续到当前语句结束。当该行执行完毕后编译器会立即调用析构函数释放资源因此匿名对象适合“临时用一下”的场景。• 下面通过一个对比示例直观展示有名对象和匿名对象在生命周期与资源释放时机上的差异#include iostream using namespace std; class A { public: A(int x 0) : _x(x) { cout A(int) 构造 _x _x endl; } ~A() { cout ~A() 析构 _x _x endl; } void show() const { cout show() _x _x endl; } private: int _x; }; void func(const A a) { cout func 调用中 endl; } int main() { cout --- 有名对象 --- endl; A named(1); // 有名对象生命周期从定义处开始 named.show(); // 可以多次使用 named.show(); // 作用域结束前一直有效 cout --- 匿名对象 --- endl; A(2).show(); // 匿名对象仅当前这一行有效行末立即析构 func(A(3)); // 匿名对象作为实参函数调用结束后析构 cout --- main 结束前 --- endl; // 此时 named 仍存活直到 main 结束才析构 return 0; } // 输出结果 // --- 有名对象 --- // A(int) 构造 _x 1 // show() _x 1 // show() _x 1 // --- 匿名对象 --- // A(int) 构造 _x 2 // show() _x 2 // ~A() 析构 _x 2 // 匿名对象 A(2) 行末立即析构 // A(int) 构造 _x 3 // func 调用中 // ~A() 析构 _x 3 // 匿名对象 A(3) 函数调用结束后析构 // --- main 结束前 --- // ~A() 析构 _x 1 // 有名对象 named 在 main 结束时才析构• 对比可见有名对象named从定义处开始存活直到其作用域这里是 main 函数结束才调用析构函数释放资源期间可以反复使用而匿名对象A(2)、A(3)没有名字生命周期只持续到当前语句结束行末或函数调用结束后编译器会立即调用析构函数释放资源。因此如果只是临时用一下对象使用匿名对象可以更及时地释放资源、减少内存占用。7.对象拷贝时的编译器优化• 现代编译器会为了尽可能提高程序的效率在不影响正确性的情况下会尽可能减少一些传参和传返回值的过程中可以省略的拷贝。• 如何优化 C 标准并没有严格规定各个编译器会根据情况自行处理。当前主流的相对新一点的编译器对于连续一个表达式步骤中的连续拷贝会进行合并优化有些更新更激进的编译器还会进行跨行跨表达式的合并优化。• 不同编译器对拷贝优化的典型行为对比如下编译器默认优化行为关闭优化的编译选项GCC默认开启拷贝省略copy elision对连续表达式中的拷贝进行合并优化在 C17 下对按值返回的临时对象保证省略拷贝。-fno-elide-constructorsClang默认行为与 GCC 基本一致开启拷贝省略对临时对象和按值返回的优化较为积极。-fno-elide-constructorsMSVC默认开启返回值优化RVO和命名返回值优化NRVO但具体行为受 /O1、/O2 等优化级别影响。/Zc:noElideConstructors或使用 /Od 关闭优化• 下面通过一个具体示例直观对比开启优化默认和关闭优化-fno-elide-constructors时传参和返回值过程中的拷贝次数差异。#include iostream using namespace std; class A { public: A(int x 0) : _x(x) { cout A(int) endl; } A(const A a) : _x(a._x) { cout A(const A) 拷贝构造 endl; } ~A() { cout ~A() endl; } int _x; }; // 传参按值接收会触发拷贝构造 void func(A a) { cout func 内 _x a._x endl; } // 返回值返回局部对象可能触发拷贝构造 A getA() { A tmp(10); return tmp; } int main() { cout --- 传参 --- endl; A obj1(1); func(obj1); // 把 obj1 拷贝给形参 a cout --- 返回值 --- endl; A obj2 getA(); // 把 getA 的返回值拷贝给 obj2 cout --- main 结束 --- endl; return 0; }• 编译运行对比# 默认开启优化拷贝省略生效 g test.cpp -o test_default ./test_default 关闭拷贝优化 g test.cpp -fno-elide-constructors -o test_noelide ./test_noelide• 开启优化默认时编译器会尽量省略中间拷贝输出大致如下--- 传参 --- A(int) func 内 _x 1 --- 返回值 --- A(int) --- main 结束 --- ~A() ~A() ~A()• 关闭优化-fno-elide-constructors时传参和返回值过程中的拷贝不会被省略输出大致如下--- 传参 --- A(int) A(const A) 拷贝构造 func 内 _x 1 --- 返回值 --- A(int) A(const A) 拷贝构造 --- main 结束 --- ~A() ~A() ~A() ~A()• 对比可见开启优化后传参时省略了形参的拷贝构造返回值时也省略了临时对象的拷贝构造整体少调用了两次拷贝构造析构次数也随之减少程序运行效率更高。• Linux 下可以将上面代码拷贝到 test.cpp 文件编译时用 g test.cpp -fno-elide-constructors 的方式关闭构造相关的优化。

相关新闻

Java电影院购票系统从零搭建:核心逻辑与代码实现

Java电影院购票系统从零搭建:核心逻辑与代码实现

简介:这是一套基于SpringBoot开发的电影院购票系统完整源码,面向计算机、电子信息工程等专业学生,适用于毕业设计、课程设计及期末大作业等实践场景。系统采用B/S架构与MVC模式,整合Java、MySQL、MyBatis、Vue、Ajax等主流技术栈&…

2026/11/10 19:03:36 阅读更多 →
办公必备!支持Word/Excel的批量打印解决方案

办公必备!支持Word/Excel的批量打印解决方案

软件介绍 文档批量打印工具「电脑」是一款专为Windows系统打造的轻量级办公辅助工具,专注于解决多文档快速打印难题。它支持批量处理Word、Excel、WPS等格式的文档和表格,集成双面打印、黑白模式等实用功能,帮助用户大幅提升办公效率。 极…

2026/11/13 12:44:25 阅读更多 →
克劳德核心词汇:提示词工程与Claude Code实战指南

克劳德核心词汇:提示词工程与Claude Code实战指南

“Show HN:克劳德的核心词汇”,名字听起来像是个提示词收藏夹,但实际上它更接近一份“Claude 使用频率最高的关键词清单 提示词工程模板”。这类项目在 Hacker News 上出现,通常不是为了介绍模型本身,而是帮你解决一个…

2026/10/26 12:02:16 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/11/13 5:13:25 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/11/13 5:13:25 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/13 5:13:25 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/11/12 18:22:26 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/11/12 18:22:25 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/11/13 5:13:25 阅读更多 →

日新闻

周新闻

月新闻