C++拷贝构造函数、无名临时对象以及NRV优化分析

自己动手理解NRV优化 自己动手理解NRV优化2010.6.29一、NRV的简单理解    NRV是Nameed Return Value的简称。NRV优化简单的说:有一条语句,A a = f();其中f()是一个函数,函数里边申请了一个A的对象b,然后把对象b返回。在对象返回的时候,一般情况下要调用拷贝函数,把函数f()里边的局部对象b拷贝到函数外部的对象a。但是如果用了NRV优化,那就不必要调用拷贝构造函数,编译器可以这样做,把a的地址传递进函数f(),然后不让f()申请要返回的对象b的空间,用a的地址来代替b的地址,这样当要 阅读详情


一:合成 Default Copy Constructor


那么什么时候编译器会为一个 class 生成一个 default copy constructor 呢?

和 default constructor 一样,C++ Standard 上说,如果 class 没有声明一个 copy constructor,就会有隐含的声明(implicitly declared)或隐含的定义(implicitly defined)出现,和以前一样,C++ Standard 把 copy constructor 区分为 trivial 和 nontrivial 两种,只有 nontrivial 的实体才会被合成于程序之中,决定一个 copy constructor 是否为 trivial 的标准在于 class 是否展现 “bitwise copy semantics”,即位逐次拷贝语义。如果没有展现,编译器将会为其合成 default copy constructor。


其实,bitwise copy = 浅拷贝,memberwise copy = 深拷贝 :)


什么时候一个 class 不展现出 “bitwise copy semantics” 呢,有四种情况:

  1. 当 class 内含一个 member object 而后者的 class 声明有一个 copy constructor 时
  2. 当 class 继承自一个 base class 而后者存在有一个 copy constructor 时 
  3. 当 class 声明了一个或多个 virtual functions 时
  4. 当 class 派生自一个继承串链,其中有一个或多个 virtual base classes 时

情况1,2比较易懂,和 constructor 类似,无非就是要安插别人的 copy constructor,所以要编译器为其合成 default copy constructor。
现在来说说 3 和 4这两种情况。

假如现有一个 virtual base 类 ZooAnimal,和一个 derived 类Bear,那么有以下情况,并且下面情况都是具有 virtual 属性的,符合 3 和 4 情况 :

无需合成的情况:

ZooAnimal class object 以另一个 ZooAnimal class object 作为初值,或 Bear class object 以另一个 Bear class object 作为初值,都可以直接靠 “bitwise copy semantics” 完成,所以这个时候编译器不会为我们合成 copy constructor(但是要使用编译器的 default constructor必须注意类型于指针情况,比如字符串指针,指针如果直接赋值它们会指向一个字符串,析构函数如果内部 delete 可能会出现问题)。因为原对象和拷贝后的对象为同一 class 类型的对象,它们调用相同的虚函数,这都是它们的类共有的函数,是一模一样的,所以浅拷贝足矣。


//简单的 bitwise copy 还不够
//编译器必须明确地将 little_critter 的
//virtual base class pointer/offset 初始化
RedPanda little_red;
Raccoon little_critter = little_red;


父类以子类内容做初始化操作情况:

    ZooAnimal franny = yogi;    //译注:这会发生切割(sliced)行为

当一个 base class object 以其 derived class 的 object 内容做初始化操作时,其 vptr 复制操作必须保证安全。父类的 vptr 不可以指向子类的 virtual table。因为父类声明一个对象需要调用自己的 virtual function,如果编译器不合成默认拷贝构造函数,那么父类的 vptr 会指向子类的 virtual table,再调用就会调用子类的 virtual function,这叫“炸毁”。


这种情况比较难理解,下面我来举个例子:

class base {   
public:  
    base(int i) : int_base_(i) {}  
    virtual void foo() { std::cout<<"base"<<std::endl; }   
    virtual ~base() = default;  
protected:  
    int int_base_;   //data member also can be overrided  
};  
  
class derived : public base {   
public:  
    derived(int i) : int_(i), base(4) { }    
    ~derived() = default;  
    void foo() { std::cout<<"derived"<<std::endl; }   
private:  
    int int_;  
};  

void do_polymorphic(base& ptr)  
{  
    ptr.foo();  
}  
  
int main()  
{  
    derived dr(5);  
    base b = dr; 
    do_polymorphic(b);
    return 0;
}
这段代码子类 override 了虚基类父类的 foo 方法,如果编译器没有为我们合成 default copy constructor 去为父类明确设定 vptr 指向父类自己的 virtual table ,而是按照 bitwise copy 的话,父类调用 foo 方法将会调用子类的 foo 方法,因为 bitwise copy 即浅拷贝的方式只是会将父类的 vptr 简单的指向子类的 virtual table(相当于指针赋值)。

但是输出结果是这样的:

这证明了在当 class 声明了一个或多个 virtual functions 时,父类使用子类初始化,编译器需要合成 default copy constructor。


处理 Virtual Base Class Subobject

最后这一种特殊情况是,在一个继承串链中,一个 class object(派生自虚基类)如果以另一个 object 作为初值,而后者有一个 virtual base class subobject,那么也会使 “bitwise copy” 失效,编译器此时需要合成default copy constructor。
如图:

再强调一次,如果以一个 Raccoon object 作为另一个 Raccoon object 的初值,浅拷贝绰绰有余了(它们是同一类)。
如果企图以一个 RedPanda object 作为 little_critter 的初值,编译器必须判断 “后续当程序员企图存取其 Zooanimal subobject 时能否正确的执行”:
//简单的 bitwise copy 还不够
//编译器必须明确地将 little_critter 的
//virtual base class pointer/offset 初始化
RedPanda little_red;
Raccoon little_critter = little_red;
在这种情况下,为了完成正确的 little_critter 初值设定,编译器必须合成一个 copy constructor,安插一些码以设定 virtual base class pointer/offset 的初值(或者只是简单地确定它没有被抹消)。
最后这种情况这一理解为,编译器为了防止 virtual base subobject 在执行期间放到正确的位置并且不被破坏,而采取的合成 default copy constructor 操作。


二:程序转化语意学


关于临时对象的总结:

首先给出我测试所用的类,下文测试代码仅给出部分,均在主函数中运行,主函数结束会进行析构操作:
class base {   
public: 
    base() { std::cout<<"base"<<std::endl; }
    base(int i) : int_base_(i) { std::cout<<"base"<<std::endl; }   
    base(const base& othread) { std::cout<<"copy base"<<std::endl; }
    virtual void foo() const { std::cout<<"foo: base"<<std::endl; }   
    virtual ~base() { std::cout<<"~base"<<std::endl; }   
protected:  
    int int_base_;   //data member also can be overrided  
};  

1.使用一个临时对象来初始化一个新对象时,编译器一般会优化为直接使用临时对象的参数来创建新对象,实际上不会生成临时对象。

如:
{
    std::cout<<"x0 begin"<<std::endl;
    base x0 = base(5);      //甚至 base x0(base(5)) 这种拷贝构造初始化也会被优化
    std::cout<<"x0 end"<<std::endl;
    std::cout<<"main end"<<std::endl;
}
输出:

base 生成之后,在函数结束后析构掉,编译器优化掉临时对象,只生成了一个对象。


2.使用一个临时对象来赋值一个对象时,临时对象创建完会直接被销毁掉。

如:
{
    base x0; 
    std::cout<<"x0 begin"<<std::endl;
    x0 = base(5);
    std::cout<<"x0 end"<<std::endl;
    std::cout<<"main end"<<std::endl;
}
输出:



3. 类对象作为函数参数按值传递时,使用临时对象作为函数使用的副本

// C++ 伪码,假如要调用 X xx; foo(xx);
//编译器产生出来的临时对象
X __temp0;

//编译器对 copy ocnstructor 的调用
__temp0.X::X( xx );

//被调用的函数实际上为
foo( __temp0 )
测试如下:
void do_polymorphic(base ptr)
{   
    std::cout<<"fun begin"<<std::endl;
    ptr.foo();  
    std::cout<<"fun end"<<std::endl;
}

main()
{
    base b;
    std::cout<<"after declare"<<std::endl;
    do_polymorphic(b);
    std::cout<<"call fun end"<<std::endl;
    std::cout<<"main end"<<std::endl;
}
输出:


注意两点:
  1. 引用传递可以避免 __temp0 临时对象的产生,不会调用拷贝构造函数。
  2. __temp0 是在 main() 函数内,未调用 do_polymorphic() 函数前产生的,并且在该函数调用完毕后立即销毁,类似于上面的 2 。(用 GDB 可以调试查看)



返回值的初始化

已知下面这个函数定义:
X bar()
{
    X xx;
    //处理 xx ...
    return xx;
}
如何将 bar() 的返回值如何从局部对象 xx 中拷贝过来?解决方案是双阶段转化:
  1. 首先加上一个额外参数,类型是类的一个引用,这个参数用来放置被拷贝构造而得的返回值。
  2. 在 return 指令之前安插一个拷贝构造操作,以便将欲传回的对象的内容当作上述新增参数的初值。
根据这样的算法,bar() 转化如下:
//函数转换
//以反应出 copy constructor 的应用
//C++ 伪码
void bar( X& __result )  //在这里加上额外参数
{
    X xx;

    //编译器所产生的 default constructor 操作
    xx.X::X();

    // ... 处理 xx 

    //编译器所产生的 copy constructor 操作
    __result.X::XX( xx );

    return;
}
现在我们的编译器在外部调用该函数就会就这样的转化:
//原语句
X xx = bar();

//编译器转化为以下两个指令句
X xx;
bar( xx );
好的,上面这些就是返回值初始化的原理。

上述代码要先构造局部变量 xx,然后返回时又将其拷贝到 __result 作为返回值,效率很低。有两种解决方案:
  1.  在程序员层面做优化,直接计算 __result。(其实就是类似 return X(); ,这种做法,返回的时候构造一次就可以了)。
  2. 编译器层面做优化,即 NRV(Name Return Value)优化。编译器可以在 return 指令传回相同的临时有名对象(即 xx 对象)的情况时,直接处理 __result,不生成对象xx。NRV 优化要求 class 必须具备拷贝构造函数。

NRV优化:
对于下列代码:
base x0, x1;
base x2 = add(x0, x1);
如果编译器未开启NRV优化,会生成如下东东:
base __temp0;     // 构造函数.
add(__temp0, x0, x1);
base (__temp0);  // 拷贝构造函数.
而开启NRV优化后,只会生成下列代码:
add(x2, x0, x1);
所谓的NRV优化,即保存返回值的变量不再使用编译器内部生成的__temp0这样的东西,而是直接把 x2 直接作为返回变量。

书中说,NRV优化和拷贝构造函数是有关系的,只有定义了拷贝构造函数才会开启NRV优化,但现代编译器NRV优化的开启一般都与拷贝构造函数没有关系,下面一段话摘自网络,参考关于cfront的NRV优化,解释了为什么lippman在书中说有关的原因:
  • “早期的 cfront需要一个开关来决定是否应该对代码实行NRV优化,这就是是否有客户(程序员)显式提供的拷贝构造函数:如 果客户没有显示提供拷贝构造函数,那么cfront认为客户对默认的逐位拷贝语义很满意,由于逐位拷贝本身就是很高效的,没必要再对其实施NRV优化;但 如果客户显式提供了拷贝构造函数,这说明客户由于某些原因(例如需要深拷贝等)摆脱了高效的逐位拷贝语义,其拷贝动作开销将增大,所以将应对其实施NRV 优化,其结果就是去掉并不必要的拷贝函数调用。”
  • 需要说明的一点:NRV优化会导致原本预想中的调用“拷贝构造函数”变成调用别的“构造函数”,一旦这个时候,拷贝构造函数和别的构造函数提供的功能不同,就可能会出问题。
目前 NRV 优化是 g++ 的默认行为。


三:copy constuctor 要还是不要?


什么时候我们应该为 class 提供一个 explicit copy constructor 呢? 如果是编译器自动为你实施了最好的行为,那么就不需要自己定义 copy constructor,尤其是成员类型为 POD 类型的时候。不过,如果类的某个方法想要开启 NRV 优化,那倒是可以定义 copy constructor。甚至针对简单类型可以在 copy constructor 中直接用 memset 函数,但是memset 绝对不能用在 virtual class 中,因为别忘了 vptr 的存在。



四:成员初始化列表的队伍


下列情况下,为了让你的程序能够顺利被编译,你必须使用成员初始化列表:
  1. 当初始化一个 reference 成员时
  2. 当初始化一个 const 成员时
  3. 当调用一个基类的构造函数,而它拥有一组参数时
  4. 当调用一个成员类的构造函数,而它拥有一组参数时
并且要注意,成员初始化的顺序和初始化列表无关,只依赖于它们在类中声明的顺序。
(拓展知识:继承时,继承的类构造顺序也和继承的顺序一致,比如:public A, public B,那么构造顺序就是A,B。但是一旦有 virtual 继承出现,该 virtual base class 会首先被构造,因为我们要确保 virtual table 的位置正确放置)


深度解读《深度探索C++对象模型》之C++返回值优化 返回值优化是什么意思?编译器在什么情况下会启用返回值优化,返回值优化能获得多少性能的提升?它有什么优缺点?本篇将从背后的机制来深入分析。 阅读详情

相关推荐

C++ 临时性对象

分析下列3个语句产生的临时对象: 1.T c = a + b; 2.c = a + b; 3.a + b; 对于 T c = a + b; C++标准允许编译器厂商有完全的自由度: •编译器可以产生一个临时对象,放置a+b的结果,然后再使用T的copy constructor,把该临时性对象当作C的初始值 •编译器也可以直接以拷贝构造的方式,将a+b的值放到C中(2.3节),于是不需要临时对象,以及对其的constructor和destructor •视operator+()的定义而定,NRV(named

希望我的博客,能帮上你解决学习中工作中所遇到的问题 312

编译器对于C++构造函数的优化和C++17之后对构造函数的优化

近日结合李伟老师在C++构造函数课上讲的内容,跑了一些程序,发现了一些疑问。 程序如下 #include <iostream> using namespace std; class str { public: str(int x):a(x) { cout<<"construct function"<<endl; } str(const str& str1):a(str1.a) { co

liangjian990709的博客 1417

Fluent Meshing边界层设置保姆级教程:从y+理论到实战避坑,看完就会

本文详细解析了Fluent Meshing边界层设置的全过程,从y+理论基础到实战避坑技巧,帮助用户精准计算第一层高度并优化参数配置。通过案例演示和常见问题诊断,指导读者掌握边界层网格生成的核心技术,提升CFD模拟精度。特别针对不同湍流模型的y+要求提供具体参数建议。

weixin_30576827的博客 790

关于构造函数和拷贝构造函数引发的编译器优化

编译器优化之拷贝构造

zhengyawen666的博客 407

OpenClaw 企业级自动化系统架构设计与实现

本文介绍基于 OpenClaw 构建的企业级自动化系统的完整架构设计、技术选型、实现细节和性能优化方案。

2604_95445636的博客 483

Prokka实战:10分钟搞定细菌基因组注释(附详细参数解析)

本文深入解析Prokka细菌基因组注释工具的核心参数与实战策略。通过拆解其集成化工作流程,详细解读物种分类、功能注释、输出控制等关键参数,并提供快速初筛、高质量发表、质粒注释及批量处理四种典型场景的高效参数组合方案,帮助用户精准掌控注释过程,将原始序列转化为有价值的生物学见解。

weixin_29271053的博客 442

C++移动构造函数问题,编译优化导致不一致

在学习到拷贝够造函数的时候,死活就不是按照B站清华大学的一个C++进阶班老师说的一样,getNum为一个局部函数,里面创建的对象,在函数返回时被释放,从而调用拷贝构造函数,返回一个临时对象,用临时对象调用getInt()输出0,在主函数结束的时候,临时构造的对象会调用析构函数。 用clock block运行 如图下图: 查阅资料,知道原来有些编译器会对代码进行优化,并不会调用构造函数,用vs20...

qq_1316238389的博客 620

【Python程序开发】湖南省职业院校技能大赛python程序开发赛项样题二

【Python程序开发】湖南省职业院校技能大赛python程序开发赛项样题二

况老师话竞赛&blog 2197

一文搞懂C++临时对象优化 附详细样例

C语言和C++在程序执行中,都是通过调用一系列的函数来实现的。并且,很多时候,编译器会帮助我们做一系列的事情,比如(在编译类的成员方法的时候,编译器默认添加 this 指针,以此来确定是哪一个对象调用了该成员方法)。得益于编译器或者说系统帮助我们做的一系列事情,我们可以更加方便地使用C++。但是凡事有利必有弊,因为系统有时候会自己调用一系列的函数,从另一个角度来说,也一定程度上降低了效率。 而我们想要提高C++的执行效率,就需要了解程序(主要是对象)使用过程中都调用了哪些方法。VS2019 x86环境下,编

哇咔咔的博客 640

图像质量评估:使用 SSIM 计算图像相似性

在图像处理领域,衡量两幅图像之间相似性的一种常见方法是使用结构相似性指数(SSIM)。SSIM 是一种全参考的图像质量评估指标,它不仅考虑了图像的亮度、对比度,还考虑了结构信息。在本文中,我们将介绍一个使用 Python 和 OpenCV 实现的 SSIM 计算脚本,并使用该脚本评估两幅图像的相似性。

hasque2019的博客 1153

JSSIP实战:5分钟搞定WebRTC电话功能(附完整代码示例)

本文通过JSSIP库实战演示如何在Web应用中快速集成WebRTC电话功能。文章提供了从环境准备、SIP服务器连接到完整代码示例的详细步骤,涵盖用户注册、拨号接听、媒体流处理等核心环节,并针对常见问题给出排查方案,帮助开发者高效实现网页端实时语音通信。

u8v9w0x1y的博客 517

C++构造函数传参与返回值时的优化

总结C++对传参和传返回值时构造的优化处理 这里用具体例子说明,简单定义一个日期类: class Date { public: Date(int year = 0, int month = 0, int day = 0) :_year(year) , _month(month) , _day(day) { co...

Guijun6的博客 1223

手把手教你完成YOLOv9 PyQt5目标检测界面搭建,实现图片检测、视频检测、摄像头检测,可用于大论文凑工作量或毕设必备,全网最详细教程

目标检测是计算机视觉中的重要任务,广泛应用于安防监控、自动驾驶、智能家居等领域。YOLO系列模型由于其高效的检测速度和较高的准确率,成为目标检测任务的首选算法之一。本项目结合 YOLOv9与 PyQt5,构建了一个图形化界面,便于用户进行目标检测的操作和展示,实现对图片、视频和摄像头的实时目标检测,不仅可以用于大论文的工作量展示,还可以作为毕业设计。

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 2657

GCC编译器下NRV优化

关于NRV优化的相关测试以及思考

weixin_46715151的博客 973

调整开关频率处理传导骚扰超标的系统方法

针对某产品在传导骚扰测试中660kHz频点超标问题,分析发现与DC-DC模块开关频率直接相关。通过调整模块开关频率至500kHz,使其避开标准限值严苛频段(0.53-1.8MHz),在不改变硬件设计的情况下实现测试通过。该案例表明,利用EMC标准的频率特性进行"频谱设计"比传统滤波手段更高效,建议在多模块系统中采用1:2:4等频率规划策略,从源头降低噪声耦合风险。这一频率迁移思路为EMC优化提供了新范式。

硬核科技 330

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

深度解读《深度探索C++对象模型》之C++的临时对象(一)

所谓临时对象就是当编译器需要一个空间来暂存表达式的求值结果时临时创建的一个未命名的对象。编译器根据程序的需要可能会安插一些临时变量来支持程序的运行,这些动作是在程序员不可感知的背后默默进行,所以我们有必要了解编译器在背后的所作所为。这些动作有时是为了转换原来的代码的语义以保证代码能顺利地编译通过,有的是为了程序运行的正确性而暂存的对象。

iShare_Carlos的博客 1454

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

深入探索C++对象模型一书中拷贝构造函数和NRV关系探讨

转自:http://blog.guorongfei.com/2016/01/11/cpp-copy-constructor-nrv/ 最近深入探索C++对象模型一书,对于P67中最后一段话的第一句非常不解 这个程序的第一个版本不能实施 NRV 优化,因为 test class 缺少一个 copy constructor 从这段文字来看如果没有拷贝构造函数就不会有 NR

早起的虫儿灬 542

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

IDEA的使用指南

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

关于NRV优化详细分析

在C++中,函数返回整数或指针是通过eax寄存器进行传递的,理解起来比较简单。     但是返回对象或结构体一直是令人感到困惑的问题。今天我整理了一下,将整个返回过程写下来,以作备用。       还是先通过一个例子来理解这个问题: 首先,定义一个类Vector: class Vector { public: int x,y; }; 然后定义函数add(

FreeeLinux's blog 2009

临时对象与NRV技术

临时对象与NRV技术   《More Effective C++》中讲到,在C++中真正的临时对象是看不见的,它们不出现在你的源代码中。建立一个没有命名的非堆(non-heap)对象会产生临时对象,这种未命名的对象通常在两种条件下产生:为了使函数成功调用而进行隐式类型转换和函数返回对象时。 1 size_t countChar(con...

weixin_30702413的博客 106

参数返回值及NRV优化(named return value optimization)

C++11中的移动构造函数又把NRV优化翻出来了,都是采用临时中间值优化,两者不能共存。 参数传递如何实现? 【实现模型1】引入临时对象,使用拷贝构造函数初始化。然后利用bitwise copy将其拷贝到x0的位置。比如: void foo( X x0 ); X xx; foo( xx ); 改写成 X __temp0; __temp0.X::X ( xx ); foo( __t

hustyangju的足迹 1349

NRV优化

在C++中,函数返回整数或指针是通过eax寄存器进行传递的,理解起来比较简单。     但是返回对象或结构体一直是令人感到困惑的问题。今天我整理了一下,将整个返回过程写下来,以作备用。       还是先通过一个例子来理解这个问题: 首先,定义一个类Vector:   1 2 3 4 5 clas

caoyan_12727的博客 836

Inside the C++ Object Model学习:2.3 程序转换语义(续):编译器层面的优化——具名返回值优化(NRV)

看下面这个函数 : 这个函数有一个特点:函数体里所有的 语句,返回的都是同一个具名的局部对象——这里就是 。当一个函数满足"所有 语句返回的都是同一个具名局部变量"这个条件时,编译器就可以做一种非常划算的优化:压根不需要真的把 单独造出来、再想办法搬运给调用者,而是直接拿调用者那边准备好接收结果的那块内存,当作 本身来用。 用编译器实际会生成的等价代码来表达这个思路,大概是这样: 对比一下前后两个版本,能看出编译器做了两件事:下面写一段完整、可以编译运行的代码,模拟编译器优化前后两种版本的行为,验证

虾球 288

《深入C++面向对象模型》之拷贝构造函数

花了几天时间,把《深入C++面向对象模型》看了一半的样子。确实如BBS上的同学说的那样,“帅呆了!”,绝对让你停不下来的节奏。这本书是C++经典书单里面的常客,《Effective C++》也是很多人推荐。说实话吧!我手头有一本《Effective C++》,却一直没有看完,准确地说是我没有在阅读的过程中得到很多乐趣。不是黑《Effective C++》,只是这本书的写作模式是条款式的。它的关注点

intheworld 857

深入探索C++对象模型-构造函数 阅读笔记

深入探索C++对象模型-构造函数 阅读笔记 文章目录深入探索C++对象模型-构造函数 阅读笔记默认构造函数什么情况下编译器需要合成默认构造函数?注意拷贝构造函数什么情况下编译器需要合成拷贝构造函数?注意具名返回值(Named Return Value,NRV)优化问题注意初始化列表什么情况下必须使用初始化列表?注意 默认构造函数 什么情况下编译器需要合成默认构造函数? 一句话:编译器只会去合成non trivial的默认构造函数。 且用户定义的默认构造函数(即使里面什么都没做)为non-trivial!

毛财胜的专栏 1248

深度探索C++对象模型(6)——对象(6)——程序优化

1.程序员角度优化 优化前: #include &lt;iostream&gt; #include &lt;time.h&gt; using namespace std; class A { public: int val1; int val2; public: A(int v1=0,int v2=0) :val1(v1),val2(v2) { cout &lt;&lt;...

波波鱼的博客 200
上一篇: C++编译器默认构造函数合成机制分析
下一篇: C++对象模型Data语意学分析、虚继承底层实现机制
FreeeLinux
博客等级 码龄11年 421粉丝 356原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值