《Effective C#》Item 12:推荐使用成员初始化语句

Effective C++与现代C++实践:从RAII到智能指针的编程哲学 在C++编程中,资源管理和内存安全是构建健壮系统的核心基础。RAII(Resource Acquisition Is Initialization)作为一种关键编程范式,通过将资源生命周期与对象绑定,从根本上解决了资源泄露问题。这一原理在现代C++中通过智能指针(如std::unique_ptr、std::shared_ptr)得到了优雅实现,它们不仅自动管理动态内存,还通过所有权语义确保了异常安全。这些技术对于开发高性能服务器、游戏引擎等对稳定性要求极高的应用场景至关重要。本文以《Effective C+ 阅读详情

为了方便内容的开展,先说说一个对象的构造过程。

对于类型第一个实例的构造过程大致如下:

1. 分配静态成员的内存空间,此时空间存储数据为0;

2. 执行静态成员的初始化语句;

3. 执行基类的静态构造函数;

4. 执行类型的静态构造函数;

5. 分配成员的内存空间,此时空间存储数据为0;

6. 执行成员的初始化语句;

7. 执行相应的基类构造函数;

8. 执行类型的构造函数。

 

那么对于同类型的后续创建对象,前4个步骤不用执行的,直接从第5步开始。

(这里有些出入,对于如下例子:

    public class clsA

    {

       private static readonly string strA = "A";

       static clsA()

       {

           Debug.WriteLine( strA );

           strA = "A Changed!";

           Debug.WriteLine( strA );

           Debug.WriteLine( "A static constructor!" );

       }

 

       public clsA()

       {

           Debug.WriteLine( "A constructor!" );

       }

    }

 

    public class clsB:clsA

    {

       private static readonly string strB = "B";

       static clsB()

       {

           Debug.WriteLine( strB );

           strB = "B Changed!";

           Debug.WriteLine( strB );

           Debug.WriteLine( "B static constructor!" );

       }

       public clsB():base()

       {

           Debug.WriteLine( "B constructor!" );

       }

    }

 

结果输出为:

B

B Changed!

B static constructor!

A

A Changed!

A static constructor!

A constructor!

B constructor!

 

这里的顺序并不完全符合书中所说,区别主要在于基类静态成员以及静态构造函数的调用,这些语句是在构造函数成员初始化语句中才被调用,即“base()”这句的时候才被调用,这也比较符合静态成员初始化以及静态构造函数的调用,即首次访问此类型的时候才被调用。

因此我觉比较合理的对象构造过程应该如下。

1.  分配静态成员的内存空间,此时空间存储数据为0;

2.  执行静态成员的初始化语句;

3.  执行类型的静态构造函数;

4.  分配成员的内存空间,此时空间存储数据为0;

5.  执行成员的初始化语句;

6.  执行基类的静态构造函数;

7.  执行相应的基类构造函数;

8.  执行类型的构造函数。

 

在此多谢xyq1986网友提出的质疑)

 

现在来说说为什么推荐使用成员初始化语句来初始化成员。由于成员初始化先于构造函数的调用,所以更早初始化有利于使用;其次,避免对构造函数重复添加初始化代码,尤其是新增成员的时候,把初始化放到定义成员的位置,减少因构造函数之间的不一致,而造成某些成员未被初始化。而且把成员初始化从构造函数中抽出来,使代码显得更简洁明朗。

例如:

    public class MyList

    {

        //Init class member here

        private ArrayList _List = new ArrayList();

    }

 

是不是所有的成员都可以这样进行初始化呢。事实上,有三种场景是不适合用这样的方式来完成成员初始化。

 

第一种就是给成员赋给“0”或者“null”,这并不是错误语句,而是没有必要的。参看前面的对象构造过程,由于成员首先会被分配内存空间,并且同时已经用“0”进行初始化了。因此显式的赋值会增加指令操作,而影响效率。

 

第二种就是根据不同参数来指明成员初始化的方式,而一般类似操作是放在构造函数中。如果使用成员初始化语句的话,那么在构造函数中重新初始化成员,就会生成一个短暂的临时对象。

例如:

    public class MyList

    {

        //Init class member here

        private ArrayList _List = new ArrayList();

 

        public MyList()

        {

        }

 

        public MyList( int nSize )

        {

            _List = new ArrayList( nSize );

        }

    }

 

以上例子,如果通过“MyList( int nSize )”这个构造函数来创建对象,会先通过成员初始化来初始“_List”成员,然后在构造函数重新初始化此成员。那么实际上,会在内存中产生两个ArrayList对象,前一个已经成为垃圾,需要等待GC进行回收。对于这种情况,用如下的方式可能会更好。

    public class MyList

    {

        //Init class member here

        private ArrayList _List;

 

        public MyList()

        {

            _List = new ArrayList();

        }

 

        public MyList( int nCount )

        {

            _List = new ArrayList( nCount );

        }

    }

 

对于最后一种就是,由于通过成员初始化来初始化成员,在初始化语句地方是不能加入try-catch来捕获异常,因此在初始化过程中所出现的异常会被传递出去,为了保证程序的安全,则需要在调用端进行try-catch捕获。不过这样操作会使调用端的代码显得繁琐,更合理的做法,是在类型中对成员初始化进行异常处理,因此采用构造函数来初始化成员效果更好些。例如:

    public class MyTest

    {

        private TempObject _value;

 

        public MyTest()

        {

            try

            {

                _value = new TempObject();

            }

            catch( Exception err )

            {

                //Handle exception here

            }

        }

    }

 

对于成员初始化的好处以及其的使用限制,到此就已经说完了。不过,我个人更喜欢通过构造函数来初始化成员。对于文章中所说到的,使用构造函数来初始化成员的一些不利之处,例如:多个构造函数之间初始化操作的繁琐或者成员初始化的不统一,我觉得可以通过构造函数调用构造函数的方式来减少此类问题。不过这也只是我个人看法,至于具体用什么并没有明确的标准,只要把不同的方法合理整合到自己的应用程序中就行了。

Qt 6.5实战:用QMediaPlayer搞定RTSP监控流播放(附LAV Filters解码器避坑指南) 本文详细介绍了如何在Qt 6.5中使用QMediaPlayer实现低延迟RTSP监控流播放,并提供了LAV Filters解码器的配置避坑指南。通过优化缓冲策略和硬件加速设置,显著提升视频流的播放性能和稳定性,适用于工业视觉检测和安防监控等实时场景。 阅读详情

相关推荐

555定时器呼吸灯电路制作全攻略:从仿真到实物搭建(附避坑指南)

本文详细介绍了使用555定时器制作呼吸灯电路的完整流程,从基础原理到实物搭建,包括电路设计、元件选择、仿真验证、焊接技巧及调试优化。特别提供了避坑指南,帮助电子爱好者快速掌握这一经典DIY项目,实现美观的呼吸灯效果。

weixin_33734785的博客 402

《Effective C#》Item 2:定义常量的两种方法

在C#中定义常量的方式有两种,一种叫做静态常量(Compile-time constant),另一种叫做动态常量(Runtime constant)。前者用“const”来定义,后者用“readonly”来定义。 对于静态常量(Compile-time constant),它的书写方式如下:public const int MAX_VALUE = 10;为什么称它为静态常量呢,因为

愚翁专栏 6099

西门子1500 PLC与巴鲁夫RFID实战:从硬件接线到数据读写的完整流程

本文详细介绍了西门子S7-1500 PLC与巴鲁夫RFID系统集成的完整实战流程。内容涵盖从硬件选型、接线、PROFINET网络配置,到在TIA Portal中安装GSD文件、组态设备、分配地址,再到使用标准功能块(如FB31)进行程序架构设计、实现数据读写以及错误诊断。文章重点分享了硬件连接要点、软件配置步骤、数据块管理技巧以及调试中常见问题的解决方案,为工业自动化工程师实施RFID项目提供了清晰的指导。

weixin_29161785的博客 386

Effective C# Item12:变量初始化器优于赋值语句

之所以推荐在变量声明时进行初始化,是因为我们定义的类型往往有多个成员变量,这样会导致有多个构造器,这样成员变量和构造器之间很可能做不到同步更新。我们可以通过“在声明变量的同时初始化它们”的方式来解决这个问题。     但是,以下三种情况,是不适合在变量初始化时对其进行赋值的。 当我们要将对象初始化为0或者null时,这时在变量初始化时为其赋值是没有错的,但是效率不高。原因是系统默认的初始化

尹自强.DoSomething() 446

常见图像加密性能评价指标(详解加python实现)

前言 本文目的 介绍一些常见的用于图像加密的评价指标并予以代码实现,方便以后做实验时参考查阅。 图像加密领域所有常见的安全分析技术汇总如下图。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7N8tbKNx-1618308894314)(%E5%B8%B8%E8%A7%81%E5%9B%BE%E5%83%8F%E5%8A%A0%E5%AF%86%E6%80%A7%E8%83%BD%E8%AF%84%E4%BB%B7%E6%8C%87%E6%A0%87/1-s2.0-S0165

z2bns的博客 3万+

Tomcat启动过程中cmd窗口(控制台)中文乱码的问题

tomcat启动时,启动过程日志中文乱码的处理方法。

寻码启示 1944

[转载]《Effective C#》Item 7:推荐使用不可改变的原子值类型

《Effective C#》Item 7:推荐使用不可改变的原子值类型《Effective C#》Item 7:推荐使用不可改变的原子值类型 首先来解释一下标题,原标题为《Prefer Immutable Atomi...

congji3817的博客 99

【C2000系列DSP的Bootloader详解】如何打包源文件为库文件且加密仅授权使用,一步步教你如何实现

如果想要在 TI 的 CCS 开发环境中为 C2000 系列 MCU 生成 lib 库文件,并对这些库文件进行加密保护,确保只有授权方(持有密钥)才能调用和使用,以此保护源代码的知识产权。

昔时扬尘处 177

《Effective C#》Item 7:推荐使用不可改变的原子值类型

首先来解释一下标题,原标题为《Prefer Immutable Atomic Value Type》,因此对于标题的理解要分成三部分,第一部分为不可改变,第二部分为原子,最后一个部分为值类型。最后一部分,我不多说了,限制此章适用的范围。对于什么是不可改变类型,这里的意思是指此类型的变量一旦产生其成员就不能发生变化。至于原子类型,我以前在优快云也经常提到,例如保证操作的原子性之类的语句,那么一个原

愚翁专栏 4482

从入门到精通!Arduino 全栈开发深度指南

本文围绕 Arduino 开发撰写全攻略,从基础入门到高级应用层层递进。开篇介绍 Arduino 概念、优势及硬件家族,引导读者完成开发环境搭建与首个 LED 闪烁项目;深入讲解编程语法、I/O 控制及通信协议;详细阐述传感器、模块应用与调试优化技巧;最后以自定义库开发、低功耗设计等高级内容收尾,并给出综合项目案例与产品化思路。无论新手入门,还是开发者进阶,均可从中系统学习 Arduino 知识,掌握从理论到实践的全流程开发技能。

邓邓子的博客 2757

【系统分析师】2025年下半年真题:综合知识-答案及详解(回忆版)

本文摘要包含系统分析师考试相关题目解析,主要涵盖软件工程、数据库、网络协议和项目管理等知识点。内容包括:软件再工程与逆向工程的区别(D);GNU GPL开源协议特性(A);TCP/IP协议分层(A、B);数据库范式判定(A、B);前导图进度管理工具(C);系统规划中的数据类识别方法(B、D);关系代数除运算(C);CMM优化级特征(A);回归测试重要性(C)。这些解析帮助理解核心概念和考试重点。

数据知道的博客 6717

[转载]《Effective C#》Item 2:定义常量的两种方法

《Effective C#》Item 2:定义常量的两种方法《Effective C#》Item 2:定义常量的两种方法 在C#中定义常量的方式有两种,一种叫做静态常量(Compile-time constant),...

congji3817的博客 116

【100%通过率】2024华为OD机试真题E卷 C++语言 实现【流浪地球】

流浪地球计划在赤道上均匀部署了N个转向发动机,按位置顺序编号为0~N-1。 1) 初始状态下所有的发动机都是未启动状态; 2) 发动机起动的方式分为“手动启动”和“关联启动”两种方式; 3) 如果在时刻1一个发动机被启动,下一个时刻2与之相邻的两个发动机就会被“关联启动”; 4) 如果准备启动某个发动机时,它已经被启动了,则什么都不用做; 5) 发动机0与发动机N-1是相邻; 地球联合政府准备挑选某些发动机在某些时刻进行“手动启动”,当然最终所有的发动机都会被启动。 哪些发动机最晚被启动呢?

MISAYAONE的博客 4212

Effective C# Item14:利用构造器链

    编写构造函数通常是一件重复性的劳动,我们经常需要在不同声明形式的构造函数中,对同一个成员变量进行同样的初始化操作,为了完成这个任务,通常有以下三种方式。 对代码采用“复制/粘贴”的方式,在写好一个构造函数后,将代码粘贴到其他构造函数中。 采用辅助函数的方式,将共通的逻辑放置到一个单独的方法中,然后在每个构造函数中调用这个方法。 采用构造器链的方式,在一个构造函数中,使用另外的构造...

weixin_34227447的博客 106

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

转:《Effective C#》Item 7:推荐使用不可改变的原子值类型

转:http://dev.youkuaiyun.com/author/Knight94/5582b364fc744be09bca2dca36786322.html《Effective C#》Item 7:推荐使用不可改变的原子值类型 首先来解释一下标题,原标题为《Prefer Immutable Atomic Value Type》,因此对于标题的理解要分成三部分,第一部分为不可改变,

flyskylf的专栏 659

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

C#.NET初级开发者面试必备21~30题解析

在C#.NET开发中,理解值类型与引用类型的区别、字符串拼接优化、装箱拆箱性能损耗等基础概念至关重要。这些核心知识点不仅关系到代码效率,更是面试中的高频考点。通过哈希表实现的Dictionary、基于状态机的async/await异步编程、以及LINQ查询的延迟执行机制,都体现了.NET框架的设计精髓。合理使用StringBuilder预分配容量、采用泛型集合避免装箱、利用GC分代算法管理内存,能在实际项目中显著提升性能。本文通过典型代码示例,演示如何在高并发场景下选用ConcurrentDictionar

weixin_30595035的博客 439

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

2024年C++程序员成长路线图:从新手到架构师的完整路径

C++作为一种高性能系统编程语言,其核心价值在于对计算机底层原理的深度控制和高性能计算能力。其设计哲学融合了面向对象、泛型和过程式编程范式,通过RAII(资源获取即初始化)等机制实现安全高效的资源管理。在现代软件开发中,C++的技术价值体现在操作系统、游戏引擎、高频交易、数据库等对性能和可靠性要求极高的领域。随着AI基础设施和边缘计算的发展,掌握C++底层原理和大型系统架构能力成为工程师的核心竞争力。本文基于C++11/14/17/20的现代特性,结合多线程编程、智能指针、STL容器等热词,系统梳理了从语言

weixin_33709609的博客 521

Google亲自下场力挺:“Go才是AI辅助软件工程理想语言”,却引全网热议

因此,一门适合 AI 编程的语言,不应该只追求“让代码更容易写”,还应该让生成出来的代码更容易看懂、更容易验证,也更不容易在长期维护中失控。如果让 AI 智能体持续迭代重构代码却缺少校验手段,输出质量会快速下滑,和人类徒手重构遇到的困境如出一辙:首轮生成正确率或许能达到 95%,反复迭代后错误持续累积,占用大量上下文窗口,不仅准确率下降,还会拉高 Token 开销。得益于这项兼容性承诺,15 年前为 Go 1.0 编写的代码,不需要任何修改,就可以使用最新的 Go 工具链进行编译和运行。

优快云资讯 2493
上一篇: 优快云第一期总结之四:Stream的问题
下一篇: 《Effective C#》Item 13:使用静态构造函数初始化静态成员
Knight94
博客等级 码龄25年 1013粉丝 87原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值