Effective C++笔记简易总结以及程序演示

简介: 4、确定对象被使用前已被初始化在使用变量时不进行初始化是不好的行为,在程序中有可能读入一个未初始化的值就可能导致程序崩溃。

4、确定对象被使用前已被初始化

在使用变量时不进行初始化是不好的行为,在程序中有可能读入一个未初始化的值就可能导致程序崩溃。

对于内置类型,保证在使用对象之前进行初始化:

int x = 0;
const char* text = "A C-style string"

double d;
std::cin >> d;

对于结构体成员的初始化,要区别初始化和赋值的区别:

class PhoneNumber
{
private:
    int name;
    int number;
public:
    PhoneNumber(){name = 0;number = 0;} //这里是赋值不是初始化
    PhoneNumber():name(0),number(0){} //这里才是初始化(成员初值列)
};

在C++中,对象的成员变量的初始化动作发生在进入构造函数本体之前,上面利用成员初值列的方法初始化的效率较高,同时不浪费default构造函数做的一切

另外一种情况,C++对“定义于不同编译单元内的non-local static对象”的初始化相对次序并无明确定义。也就是如果某编译单元内的某个non-loacl static对象的初始化动作使用了另一个编译单元内某个non-local static对象,而它所用到的这个对象可能尚未被初始化,如果出现这种情况,那么问题是致命的。

解决这个的方法就是将每个non-loacl static对象搬到自己的专属函数内(该对象在此函数内被声明为static)。这些函数返回一个reference指向它所含的对象。然后用户调用这些函数,而不直接指涉这些对象。这个手法的基础在于:C++保证,函数内的local static对象“会在该函数被调用期间”、“首次遇上该对象之定义式”时被初始化:

class FileSystem{...};
FileSystem& tfs()           //这个函数用来替换tfs对象;它在FileSystem class            
{                  //中可能是个static。定义并初始化一个local static对象,                  
    static FileSystem fs;   //返回一个reference指向上述对象。
    return fs;
}
class Directory{...};
Directory::Directory(params)
{
    ...
    std::size_t disks = tfs().numDisks(); //调用对象
    ...
}
Directory& temDir()  //定义temDir对象为“函数对象”
{
    static Directory td;
    return td;
}

如此,在调用temDir对象时,C++会对tfs进行初始化,并对temDir也进行初始化

5、了解并拒接默默调用的函数

空类并不是空类,C++编译器会自动为其声明一个copy构造函数、一个copy assignment操作符和一个析构函数,如果你没有声明任何构造函数,那么编译器也会为你声明一个default构造函数(这些函数都是public且inline的)。

这些会引起一些比较容易忽视的问题:比如通过copy assignment操作符去给一个类赋值一个拥有不能进行赋值成员的类时会引起编译器的警告(类中有引用成员,将这个类用过=号赋予给另一个类时会出现错误,因为C++不允许reference改变指向对象)

解决这个“麻烦”的方法,即不想使用编译器自动生成的函数。手动声明copy构造函数和copy assignment操作符,将其为private:

class Uncopyable
{
protected:
    Uncopyable(){}
    ~Uncopyable(){}
private:
    Uncopyable(const Uncopyable&);
    Uncopyable& operator=(const Uncopyable&);
};

class HomeForSale:private Uncopyable{
    ...
};

这样,任何想尝试拷贝HomeForSale对象的行为编译器会进行报错。

6、别让异常逃离析构函数

析构函数绝对不要吐出异常。如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉异常,然后吞下他们(不传播)或者结束程序;
如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数(而非在析构函数中)执行该操作。

22、将成员变量名声明为private

class AccessLevels
{
public:
    int getReadOnly() const {return readOnly;}
    void setReadWrite(int value) {readWrite = value;}
    int getReadWrite() const { return readWrite;}
    void setWriteOnly(int value) {writeOnly = value;}

private:
    int noAccess; //对此int无任何访问
    int readOnly; //对此int做只读访问
    int readWrite; //对此int做读写访问
    int writeOnly; //对此int做只能写访问
};

写成上述这样是值得建议和安全的,有以下好处:
1、完美的封装性,不管你的成员变量以后怎么变使用者都不会知道;
2、可以为“所有可能的实现”提供弹性。
类中所有的成员变量都应该为private,不管是public还是protected都是不安全的,因为一个可以被所有人访问,另一个可以被所有“亲戚”访问,protected相比较public并不具有多好的隐秘性。

目录
相关文章
|
22天前
|
存储 网络协议 Ubuntu
【C++网络编程】Socket基础:网络通讯程序入门级教程
【C++网络编程】Socket基础:网络通讯程序入门级教程
42 7
|
2月前
|
Java 编译器 C++
C++入门指南:类和对象总结笔记(下)
C++入门指南:类和对象总结笔记(下)
30 0
|
2月前
|
存储 编译器 C语言
C++入门: 类和对象笔记总结(上)
C++入门: 类和对象笔记总结(上)
34 0
|
2月前
|
存储 缓存 算法
【C/C++ 性能优化】提高C++程序的缓存命中率以优化性能
【C/C++ 性能优化】提高C++程序的缓存命中率以优化性能
123 0
|
1月前
|
C++ 计算机视觉 Windows
【C++】由于找不到xxx.dll,无法继续执行代码,重新安装程序可能会解决此问题。(解决办法)
【C++】由于找不到xxx.dll,无法继续执行代码,重新安装程序可能会解决此问题。(解决办法)
|
5天前
|
运维 Serverless Go
Serverless 应用引擎产品使用之在阿里云函数计算中c++模板,将编译好的C++程序放进去部署如何解决
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
9 1
|
6天前
|
安全 Java 程序员
【C++笔记】从零开始认识继承
在编程中,继承是C++的核心特性,它允许类复用和扩展已有功能。继承自一个基类的派生类可以拥有基类的属性和方法,同时添加自己的特性。继承的起源是为了解决代码重复,提高模块化和可维护性。继承关系中的类形成层次结构,基类定义共性,派生类则根据需求添加特有功能。在继承时,需要注意成员函数的隐藏、作用域以及默认成员函数(的处理。此外,继承不支持友元关系的继承,静态成员在整个继承体系中是唯一的。虽然多继承和菱形继承可以提供复杂的设计,但它们可能导致二义性、数据冗余和性能问题,因此在实际编程中应谨慎使用。
7 1
【C++笔记】从零开始认识继承
|
10天前
|
安全 编译器 C++
C++从入门到精通:3.2异常处理——掌握C++的异常处理机制,提高程序健壮性
C++从入门到精通:3.2异常处理——掌握C++的异常处理机制,提高程序健壮性
|
10天前
|
存储 IDE 编译器
C++从入门到精通:1.3.1了解IDE与C++程序的编写、编译和运行
C++从入门到精通:1.3.1了解IDE与C++程序的编写、编译和运行
|
10天前
|
存储 程序员 数据库
C++从入门到精通:1.2.2简单程序与接收用户输入
C++从入门到精通:1.2.2简单程序与接收用户输入