条款4:确定对象被使用前已经被初始化

* 为内置型对象进行手工初始化,因为C++不保证初始化它们;

* 构造函数最好使用成员初始化列表(实际初始化顺序不与列表的排列顺序有关,只取决于类中的声明顺序),而不要在构造函数体内使用赋值操作;

* 未避免“跨编译单元的初始化次序”问题,请用local static代替non-local static对象。


1. 内置类型

C++中的内置基本类型,比如int,double,float等,初值都是垃圾值,即声明int i,i的初值是一个垃圾值。本书建议的最佳处理方法是:永远在使用对象之前将之初始化。比如:

int x = 0;

const char* test = “hello world”;

double d; cin >> d;

2. STL

C++提供了丰富的容器,比如vector,list,deque,map和set等,这些容器已经写好了构造函数,所以总会自动初始化成默认值,程序员可以直接使用,比如:

vector<int> vt; vt.push_back(3);

3. 自定义类

C++在类中有专门初始化成员变量的构造函数,程序员可以写出合适的构造函数,比如:

class A
{
private:
         int a;
         double b;
         string text;

public:
         A():a(0), b(0), text("hello world"){} //构造函数
};

当声明A obj;时,obj的成员变量a,b和text就已经获得了初值,分别是0,0和hello world。

这里注意一下,有些C++的初学者喜欢这样写:

class A

{
private:
         int a;
         double b;
         string text;
 
public:
          A()
          {
                   a = 0;
                   b = 0;
                   text = "hello world";
          }
 
};

效果虽然和上一个例子一样,都获得了指定的初值,但执行的效率却不如上个例子。上一个例子中使用了成员初始化列表的方式,即在冒号后面逐一初始化,但本例却在函数体内进行了初始化。事实上,本例其实不能严格称为“初始化”,因为在进入构造函数的函数体时,这些成员变量已经被初始化了,a和b初始化成垃圾值,string因为是STL,调用默认的构造函数初始化为空字符串,在函数体内进行的操作实为“赋值”,也就是用新值覆盖旧值。这也正是说它的执行效率不高的原因,既进行了初始化,又在之后进行了赋值,不像上一个例子,只有初始化,一步到位。在有些特殊情况下,比如成员变量是const的或者是reference的,进行初始化后值就不可以改变了,这时只能用初始化列表,不能在函数体内赋值。

所以,应该尽可能地采用有冒号的成员初始化列表。注意这里的用词“尽可能地”,表示也不是所有情况都用这个初始化列表,当想构造的内容复杂,或者已经模块化为函数了,这时不能用初始化列表的方式,就采用在函数体内赋值的方式为好。

这里还有一个问题要注意下,当使用初始化列表时,初始成员变量的顺序与列表排列的顺序没有关系,只取决于声明这些成员变量的顺序,还是那个例子,将之改成:

class A
{
private:
      int a;
      double b;
      string text;

public:
        A():b(0), a(0), text("hello world"){}
};

虽然初始化列表的顺序是b在先,但编译器只会根据声明变量时的先后顺序,所以还是a被先初始化,想要用以下这种方式初始化的同学要当心:

class A
{
private:
          int a;
         double b;
         string text;
 
public:
         A():b(0), a(b), text("hello world"){}

};

这一定不会得到你想要的结果的,因为a会首先初始化,而这时b尚未初始化,所以会有bug。本书中建议,为了避免这种顺序不一致的晦涩错误,“当你在成员初值列中条列各个成员时,最好总是以声明次序为次序”。

4. 不同编译单元内定义的non-local static 对象

这里先解释一下名词,static是静态的意思,表示这个变量不由栈分配,而存储在特有的全局变量/静态变量区域中,具有长寿命的特点(从被构造出来,直到程序结束时,才会由系统释放资源);而non-local则是说这个对象是全局的,而不是函数内的静态变量,是说它的作用范围广。

比如在文件1中定义了

int a = 1;

而在文件2中又会去使用:

extern int a;
int b = a *3;

可以看到文件1应在文件2之后执行,这样a才能获得初值,否则b得到的将是垃圾值,但事实上C++对于不同文件执行的相对次序并无明确定义,这样b究竟得到的是垃圾值还是3就不能确定。

解决这个问题是方法是不要使变量有全局的作用域,可以在文件1中定义:

int& GetA()
{
         static int a = 1;
         return a;
}

而在文件2中调用

int b = GetA();

这样就一定保证a的初始化在先了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Effective.C++.中文第二版,大小 1 Mb,chm 格式,作者:Scott Meyers,翻译:Lostmouse。 内容预览: 第一章 从C转向C++ 条款1:尽量用const和inline而不用#define 条款2:尽量用<iostream>而不用<stdio.h> 条款3:尽量用new和delete而不用malloc和free 条款4:尽量使用c++风格的注释 第二章 内存管理 条款5:对应的new和delete要采用相同的形式 条款6:析构函数里对指针成员调用delete 条款7:预先准备好内存不够的情况 条款8: 写operator new和operator delete时要遵循常规 条款9: 避免隐藏标准形式的new 条款10: 如果写了operator new就要同时写operator delete 第三章 构造函数,析构函数和赋值操作符 条款11: 为需要动态分配内存的类声明一个拷贝构造函数和一个赋值操作符 条款12: 尽量使用初始化而不要在构造函数里赋值 条款13: 初始化列表中成员列出的顺序和它们在类中声明的顺序相同 条款14: 确定基类有虚析构函数 条款15: 让operator=返回*this的引用 条款16: 在operator=中对所有数据成员赋值 条款17: 在operator=中检查给自己赋值的情况 第四章 类和函数:设计与声明条款 条款18: 争取使类的接口完整并且最小 条款19: 分清成员函数,非成员函数和友元函数 条款20: 避免public接口出现数据成员 条款21: 尽可能使用const 条款22: 尽量用“传引用”而不用“传值” 条款23: 必须返回一个对象时不要试图返回一个引用 条款24: 在函数重载和设定参数缺省值间慎重选择 条款25: 避免对指针和数字类型重载 条款26: 当心潜在的二义性 条款27: 如果不想使用隐式生成的函数就要显式地禁止它 条款28: 划分全局名字空间 第五章 类和函数: 实现 条款29: 避免返回内部数据的句柄 条款30: 避免这样的成员函数:其返回值是指向成员的非const指针或引用,但成员的访问级比这个函数要低 条款31: 千万不要返回局部对象的引用,也不要返回函数内部用new初始化的指针的引 条款32: 尽可能地推迟变量的定义 条款33: 明智地使用内联 条款34: 将文件间的编译依赖性降至最低 第六章 继承和面向对象设计 条款35: 使公有继承体现 "是一个" 的含义 条款36: 区分接口继承和实现继承 条款37: 决不要重新定义继承而来的非虚函数 条款38: 决不要重新定义继承而来的缺省参数值 条款39: 避免 "向下转换" 继承层次 条款40: 通过分层来体现 "有一个" 或 "用...来实现" 条款41: 区分继承和模板 条款42: 明智地使用私有继承 条款43: 明智地使用多继承 条款44: 说你想说的;理解你所说的 第七章 杂项 条款45: 弄清C++在幕后为你所写、所调用的函数 条款46: 宁可编译和链接时出错,也不要运行时出错 条款47: 确保非局部静态对象使用初始化 条款48: 重视编译器警告 条款49: 熟悉标准库 条款50: 提高对C++的认识
内容简介: 有人说C++程序员可以分成两类,读过Effective C++的和没读过的。世界顶级C++大师Scott Meyers成名之作的第三版的确当得起这样的评价。当您读过《Effective C++中文版(第3版改善程序与设计的55个具体做法)》后,就获得了迅速提升自己C++功力的一个契机。   在国际上,本书所引起的反响,波及整个计算机技术出版领域,余音至今未绝。几乎在所有C++书籍的推荐名单上,本书都会位于三名。作者高超的技术把握力、独特的视角﹑诙谐轻松的写作风格﹑独具匠心的内容组织,都受到极大的推崇和仿效。这种奇特的现象,只能解释为人们对这本书衷心的赞美和推崇。   《Effective C++中文版(第3版改善程序与设计的55个具体做法)》不是读完一遍就可以束之高阁的快餐读物,也不是用以解决手边问题的参考手册,而是需要您去反复阅读体会的,C++是真正程序员的语言,背后有着精深的思想与无与伦比的表达能力,这使得它具有类似宗教般的魅力。希望这本书能够帮助您跨越C++的重重险阻,领略高处才有的壮美风光,做一个成功而快乐的C++程序员。 Effective C++中文版(第3版改善程序与设计的55个具体做法)》一共组织55个准则,每一条准则描述一个编写出更好的C++的方式。每一个条款的背后都有具体范例支撑。第三版有一半以上的篇幅是崭新内容,包括讨论资源管理和模板(templates)运用的两个新章。为反映出现代设计考虑,对第二版论题做了广泛的修订,包括异常(exceptions)、设计模式(design patterns)和多线程(multithreading)。   《Effective C++中文版(第3版改善程序与设计的55个具体做法)》的重要特征包括:   ·高效的 classes、functions、templates 和inheritance hierarchies(继承体系)方面的专家级指导。   ·崭新的 "TR1" 标准程序库功能应用,以及与既有标准程序库组件的比较。   ·洞察 C++和其他语言(例如Java、C#、C)之间的不同。此举有助于那些来自其他语言阵营的开发人员消化吸收 C++ 式的各种解法。 目录: 译序 中英简繁术语对照 目录 序言 致谢 导读 1.让自己习惯C++ 条款01:视C++为一个语言联邦 条款02:尽量以const,enum,inline替换#define 条款03:尽可能使用const 条款04:确定对象使用已先被初始化 2.构造/析构/赋值运算 条款05:了解C++默默编写并调用哪些函数 条款06:若不想使用编译器自动成生的函数,就该明确拒绝 条款07:为多态基类声明Virtual析构函数 条款08:别让异常逃离析构函数 条款09:绝不在构造和析构过程中调用Virtual函数 条款10:令Operator=返回一个referenceto this 条款11:在Operator=中处理“自我赋值” 条款12:复制对象时勿忘其每一个成分 3.资源管理 条款13:以对象管理资源 条款14:在资源管理类中小心Coping行为 条款15:在资源管理类中提供对原始资源的访问 条款16:成对使用new和delete对象置入智能指针 条款17:以独立语句将newed对象置入智能指针 4.设计与声明 条款18:让接口容易被正确使用,不易被误用 条款19:设计class犹如设计type 条款20:宁以pass-by-reference-to-const替换Pass-by-value 条款21:必须返回对象时,别妄想返回其reference 条款22: 将成员变量声明为private 条款23: 宁以non-member、non-friend替换member函数 条款24:若有所参数皆需类型转换,请为此采用non-member函数 条款25:考虑写出一个不抛异常的swap函数 5.实现 条款26:尽可能延后变量定义式的出现时间 条款27:尽量少做转型动作 条款28:避免返回handles指向对象内部成分 条款29:为“异常安全”而努力是值得的 条款30:透彻了解inlining的里里外外 条款31:将文件间的编译依存关系降至最低 6.继承与面向对象设计 条款32:确定你的public继承塑模出is-a关系 条款33:避免遮掩继承而来的名称 条款34:区分接口继承和实现继承 条款35:考虚virtual函数以外的其他选择 条款36:绝不重新定义继承而来的non-virtual函数 条款37:绝不重新定义继承而来的缺省参数值 条款38:通过复合塑模出has-a或“根据某物实现出” 条款39:明智而审慎地使用private继承 条款40:明智而审慎地使用private继承 7.模板与泛型编程 8.定制new和delete 9.杂项讨论 A 本书之外 B 新旧版条款对映 索引
Effective C++(编程的50个细节) Effective C++(编程的50个细节)着重讲解了编写C++程序应该注意的50个细节问题,书中的每一条准则描述了一个编写出更好的C++的方式,每一个条款的背后都有具体范例支持,书中讲的都是C++的编程技巧和注意事项,很多都是自己平时不太注意但又很重要的内容,绝对经典,作者Scott Meyers是全世界最知名的C++软件开发专家之一。 电子书PDF格式下载:http://www.yanyulin.info/pages/2013/11/effective.html 1、从C转向C++ 条款1:尽量用CONST和INLINE而不用#DEFINE 条款2:尽量用而不用 条款3:尽量用NEW和DELETE而不用MALLOC和FREE 条款4:尽量使用C++风格的注释 2、内存管理 条款5:对应的NEW和DELETE要采用相同的形式 条款6:析构函数里对指针成员调用DELETE 条款7:预先准备好内存不够的情况 条款8:写OPERATOR NEW与OPERATOR DELETE要遵循常规 条款9:避免隐藏标准形式的NEW 条款10:如果写了OPERATOR NEW就要同时写OPERATOR DELETE 条款11:为需要动态分配内存的类声明一个拷贝构造函数和一个赋值函数 条款12:尽量使用初始化而不要在构造函数里赋值 条款13:初始化列表中成员列出顺序和它们在类中的声明顺序相同 条款14:确定基类有虚析构函数 条款15:让OPERATOR=返回*THIS的引用 条款16:在OPERATOR=中对所有数据成员赋值 条款17:在OPERATOR=中检查给自已赋值的情况 3、类和函数:设计与声明 条款18:争取使类的接口完整并且最小 条款19:分清成员函数,非成员函数和友元函数 条款20:避免PUBLIC接口出现数据成员 条款21:尽可能使用CONST 条款22:尽量用传引用而不用传值 条款23:必须返回一个对象时不要试图返回一个引用 条款24:在函数重载与设定参数默认值间慎重选择 条款25:避免对指针与数字类型的重载 条款26:当心潜在的二义性 条款27:如果不想使用隐式生成的函数要显示的禁止它 条款28:划分全局名字空间 4、类和函数:实现 条款29:避免返回内部数据的句柄 条款30:避免这样的成员函数,其返回值是指向成员的非CONST指针或引用 条款31:千万不要返回局部对象的引用,也不要返回函数内部用NEW初始化的指针 条款32:尽可能推迟变量的定义 条款33:明智的使用INLINE 条款34:将文件间的编译依赖性阡至最低 5、继承与面向对象设计 条款35:使公有继承体现是一个的函义 条款36:区分接口继承与实现继承 条款37:绝不要重新定义继承而来的非虚函数 条款38:绝不要重新定义继承而来的缺省参数值 条款39:避免向下转换继承层次 条款40:通过分层来体现有一个和用...来实现 条款41:区分继承和模板 条款42:明智的使用私有继承 条款43:明智的使用多继承 条款44:说你想说的,理解你说的 6、杂项 条款45:弄清C++在幕后为你所写、所调用的函数 条款46:宁可编译与链接时出错,也不要运行时出错 条款47:确保非局部静态对象使用初始化 条款48:重视编译器警告 条款49:熟悉标准库 条款50:提高对C++的认识
译序 vii 中英简繁术语对照 ix 目录 xvii 序言 xxi 致谢 xxiii 导读 1. 让自己习惯c++ accustoming yourself to c++ 条款01:视c++ 为一个语言联邦 view c++ as a federation of languages 条款02:尽量以const, enum, inline替换 #define prefer consts,enums, and inlines to #defines. 条款03:尽可能使用const use const whenever possible. 条款04:确定对象使用已先被初始化 make sure that objects are initialized before they're used. 2. 构造/析构/赋值运算 constructors, destructors, and assignment operators 条款05:了解c++ 默默编写并调用哪些函数 know what functions c++ silently writes and calls. 条款06:若不想使用编译器自动生成的函数,就该明确拒绝 explicitly disallow the use of compiler-generated functions you do not want. 条款07:为多态基类声明virtual析构函数 declare destructors virtual in polymorphic base classes. 条款08:别让异常逃离析构函数 prevent exceptions from leaving destructors. 条款09:绝不在构造和析构过程中调用virtual函数 never call virtual functions during construction or destruction. 条款10:令operator= 返回一个reference to *this have assignment operators return a reference to *this. 条款11:在operator= 中处理“自我赋值” handle assignment to self in operator=. 条款12:复制对象时勿忘其每一个成分 copy all parts of an object. 3. 资源管理 resource management 条款13:以对象管理资源 use objects to manage resources. 条款14:在资源管理类中小心coping行为 think carefully about copying behavior in resource-managing classes. 条款15:在资源管理类中提供对原始资源的访问 provide access to raw resources in resource-managing classes. 条款16:成对使用new和delete时要采取相同形式 use the same form in corresponding uses of new and delete. 条款17:以独立语句将newed对象置入智能指针 store newed objects in smart pointers in standalone statements. 4. 设计与声明 designs and declarations 条款18:让接口容易被正确使用,不易被误用 make interfaces easy to use correctly and hard to use incorrectly. 条款19:设计class犹如设计type treat class design as type design. 条款20:宁以pass-by-reference-to-const替换pass-by-value prefer pass-by-reference-to-const to pass-by-value. 条款21:必须返回对象时,别妄想返回其reference don't try to return a reference when you must return an object. 条款22:将成员变量声明为private declare data members private. 条款23:宁以non-member、non-friend替换member函数 prefer non-member non-friend functions to member functions. 条款24:若所有参数皆需类型转换,请为此采用non-member函数 declare non-member functions when type conversions should apply to all parameters. 条款25:考虑写出一个不抛异常的swap函数 consider support for a non-throwing swap. 5. 实现 implementations 条款26:尽可能延后变量定义式的出现时间 postpone variable definitions as long as possible. 条款27:尽量少做转型动作 minimize casting. 条款28:避免返回handles指向对象内部成分 avoid returning “handles” to object internals. 条款29:为“异常安全”而努力是值得的 strive for exception-safe code. 条款30:透彻了解inlining的里里外外 understand the ins and outs of inlining. 条款31:将文件间的编译依存关系降至最低 minimize compilation dependencies between files. 6. 继承与面向对象设计 inheritance and object-oriented design 条款32:确定你的public继承塑模出is-a关系 make sure public inheritance models “is-a.” 条款33:避免遮掩继承而来的名称 avoid hiding inherited names. 条款34:区分接口继承和实现继承 differentiate between inheritance of interface and inheritance of implementation. 条款35:考虑virtual函数以外的其他选择 consider alternatives to virtual functions. 条款36:绝不重新定义继承而来的non-virtual函数 never redefine an inherited non-virtual function. 条款37:绝不重新定义继承而来的缺省参数值 never redefine a function's inherited default parameter value. 条款38:通过复合塑模出has-a或“根据某物实现出” model “has-a” or “is-implemented-in-terms-of” through composition. 条款39:明智而审慎地使用private继承 use private inheritance judiciously. 条款40:明智而审慎地使用多重继承 use multiple inheritance judiciously. 7. 模板与泛型编程 templates and generic programming 条款41:了解隐式接口和编译期多态 understand implicit interfaces and compile-time polymorphism. 条款42:了解typename的双重意义 understand the two meanings of typename. 条款43:学习处理模板化基类内的名称 know how to access names in templatized base classes. 条款44:将与参数无关的代码抽离templates factor parameter-independent code out of templates. 条款45:运用成员函数模板接受所有兼容类型 use member function templates to accept “all compatible types.” 条款46:需要类型转换时请为模板定义非成员函数 define non-member functions inside templates when type conversions are desired. 条款47:请使用traits classes表现类型信息 use traits classes for information about types. 条款48:认识template元编程 be aware of template metaprogramming. 8. 定制new和delete customizing new and delete 条款49:了解new-handler的行为 understand the behavior of the new-handler. 条款50:了解new和delete的合理替换时机 understand when it makes sense to replace new and delete. 条款51:编写new和delete时需固守常规 adhere to convention when writing new and delete. 条款52:写了placement new也要写placement delete write placement delete if you write placement new. 9. 杂项讨论 miscellany 条款53:不要轻忽编译器的警告 pay attention to compiler warnings. 条款54:让自己熟悉包括tr1在内的标准程序库 familiarize yourself with the standard library, including tr1. 条款55:让自己熟悉boost familiarize yourself with boost. a 本书之外 b 新旧版条款对映 索引
在创建 std::list 对象时,可以通过以下几种方式进行初始化: 1. 默认初始化:默认情况下,std::list 对象会被默认初始化。这意味着该对象将被创建,但是不会包含任何元素。可以通过 push_back() 或 push_front() 等函数向 std::list 中添加元素。 ```c++ std::list<int> my_list; // 默认初始化,不包含任何元素 my_list.push_back(1); // 向 my_list 中添加元素 ``` 2. 拷贝初始化:可以通过将一个 std::list 对象拷贝到另一个 std::list 对象来进行初始化。拷贝操作会将源 std::list 对象中的所有元素复制到目标 std::list 对象中。 ```c++ std::list<int> my_list1 = {1, 2, 3}; // 使用 initializer_list 进行初始化 std::list<int> my_list2(my_list1); // 拷贝初始化,将 my_list1 中的元素复制到 my_list2 中 ``` 3. 范围初始化:可以通过将一个范围内的元素复制到 std::list 对象中来进行初始化。 ```c++ std::vector<int> vec = {1, 2, 3}; std::list<int> my_list(vec.begin(), vec.end()); // 将 vec 中的元素复制到 my_list 中 ``` 4. 移动初始化:可以通过将一个 std::list 对象移动到另一个 std::list 对象来进行初始化。移动操作会将源 std::list 对象中的所有元素移动到目标 std::list 对象中,同时源 std::list 对象会被清空。 ```c++ std::list<int> my_list1 = {1, 2, 3}; std::list<int> my_list2(std::move(my_list1)); // 移动初始化,将 my_list1 中的元素移动到 my_list2 中 ``` 无论采用哪种方式进行初始化,在创建 std::list 对象时,需要确保所有的元素都被正确初始化,以避免在销毁 std::list 对象时访问未初始化的内存。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值