Effective C++学习笔记(一)

本文是Effective C++学习笔记的第一部分,涵盖了C++编程中的最佳实践。条款01强调内置类型使用值传递,用户自定义类型则适合引用传递。条款02推荐使用const和static以提高类型安全和效率。条款03介绍了const在不同场景下的应用,如修饰成员函数和变量。条款04着重于变量初始化的重要性,特别是对于自定义类型和静态成员的正确初始化方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

条款01

条款02

条款03

条款04


条款01

内置类型,值传递比引用传递更高效。 用户自定义类型,因为存在构造函数和析构函数,使用pass-by-reference-const会更好,尤其是使用模板时。

条款02

尽量以cosntenuminline,替换#define

class的专有常量,一般将常量的作用域限制于 class中,此时它应该为一个成员变量,为了确保其只有一份实体,应该将其设为静态变量。

const与 enum在定义常量时取代 #define inline在定义 类函数宏 时取代 #define,并且inline会有类型安全检查,符合 C++严格类型匹配的风格 在使用 inline定义函数时,可以使用 template来定义模板函数,这样就能够实现与 #define相类似的可以用于不同类型的参数的函数。

 class Game{
 private:
     static const int num = 5;   // 声明常量
     static const * const str = "Hello"; // 定义常量指针时应该即指向指针又指向内容
     enum {num2 = 5};            // 使用枚举定义常量
     int score[num];             // 使用常量
 };

其中static const只是常量声明,没有进行常量定义,应在Game的实现代码中添加

const int Game::num; // num常量的定义

条款03

const作用:

  • 修饰全局变量或常量

  • 修饰文件、函数或块中被声明为static的对象

    在函数声明中,const可与函数返回值,函数参数,函数自身(若是成员函数)相结合

    返回const变量,可降低意外,同时保持了安全性和高效性。

    const修饰成员函数,

    一是为了让该成员函数能够作用于const对象上

    二是使class接口容易理解,不容易出错。

  • 修饰类内部的staticnon-static成员变量

  • 修饰指针(双const,引用,关键

指针与迭代器:

 std::vector<int> vec;
 const std::vector<int>::iterator iter = vec.begin(); // 相当于int *const
 *iter = 10; // correct
 iter++;     // error
 std::vector<int>::const_iterator citer = vec.begin();   // 相当于const int *
 *citer = 10;    // error
 iter++;         // correct

很多函数需要有constnon-const版本,但实现时会出现大量的代码重复,此时

class TextB {
 public:
     ...
     const char& operator[](std::size_t position) const {
         ...     // 边界检验
         ...     // 标志访问信息
         ...     // 检验数据完整性
         return text[position];
     }
     char& operator[](std::size_t position)  {
         return const_cast<char &>(
             static_cast<const TextB&>(*this)[position]
             );      // 进行了两次强制类型转换,第一次将non-const转换为const并取出其中的值,第二次将取出的值去掉const属性
     }
 };

条款04

使用变量之前一定要进行初始化。

内置对象要进行手工初始化,而自定义类型的构造函数最好使用初始化列表,而不要在构造函数中使用赋值操作。

要使用成员变量初始化列表进行初始化,这样效率更高,若采用赋值的方式首先要调用默认构造函数赋初值,然后再一一进行赋值操作。此时默认构造函数赋初值这一步被浪费了。

若成员变量为constreferences,则一定得使用初始化列表进行初始化,因为他们肯定需要初值,只能被初始化,而不能被赋值。

成员初始化顺序,基类-->子类的声明次序

但是C++对定义在不同编译单元内的非局部静态对象的初始化相对次序并无明确的定义,所以需要一个简单的设计来解决该问题,为每个非局部静态对象设计一个专属函数(该对象在函数内部被设计为static),这些函数返回一个reference来指向它所包含的对象,然后用户调用这些函数,并不直接使用这些对象。

即将非静态局部对象转化为局部的静态对象,这样能够保证其在何时进行初始化。类似与设计模式中的Singleton

 
// 线程安全的懒汉式加锁实现
 // 使用instance方法返回一个单例对象
 class Singleton1 {
 protected:
     Singleton1() {
         pthread_mutex_init(&mutex);
     }
 private:
     static Singleton1 *p;
 public:
     static pthread_mutex_t mutex;
     static Singleton1* instance();
 };
 pthread_mutex_t Singleton1::mutex;
 Singleton1 Singleton1::p = NULL;
 Singleton1* Singleton1::instance() {
     if (p == NULL) {    
         // 1
         pthread_mutex_lock(&mutex);
         if (p == NULL)              // 此处的判断语句的作用:
 // 当线程A和B同时进入单例对象中,并且同时执行了第一次判断进入了加锁函数,此时假设A上锁了,B并没有获得资源,于是在1处等待,等到A创建完对象之后,B获得资源,此时A已经创建了对象,此时p已经不为空,所以必须要再次判断,否则这种情况下可能会创建多个实例,与单例模式的定义不符
             p = new Singleton1();
         pthread_mutex_unlock(&mutex);
     }
     return p;
 }
 ​
 // 线程安全的懒汉式内部静态变量实现
 class Singleton2 {
 protected:
     Singleton2() {
         pthread_mutex_init(&mutex);
     }
 private:
     static pthread_mutex_t mutex;
     static Singleton2* instance();
 };
 pthread_mutex_t Singleton2::mutex;
 Singleton2* Singleton2::instance() {
     pthread_mutex_lock(&mutex);
     static Singleton2 obj;          // 可以保证拥有静态实例,因为静态变量只会创建一次
     pthread_mutex_unlock(&mutex);
     return &obj;
 }

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值