【Effective C++】让自己习惯C++

这篇具有很好参考价值的文章主要介绍了【Effective C++】让自己习惯C++。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Item01 视C++为一个语言联邦

C++由四个次语言组成:

  • C:过程形式,没有模板、没有异常、没有重载
  • Object-Oriented C++:面向对象形式,类(构造函数和析构函数)、封装、继承、多态
  • Template:泛型编程、模板元编程
  • STL:容器、算法、迭代器和函数对象

Item02 尽量以const,enum,inline替换#define

目标是让编译器来替代预处理器,使用预处理器会存在以下问题:

1. 预处理器只进行简单的替换,变量名称不会被记录符号表,同时可能导致编译的目标文件包含常量的多份拷贝;

#define ASPECT_RATIO 1.653
// 如果没有被记录到符号表,程序遇到编译错误时,输出的错误信息1.653
// 会带来不必要的排查时间
// 替换为
const double AspectRatio = 1.653;

2. 定义字符串的采用string替换char*,避免写两次const的情况出现;

const char* const authorName = "Scott Meyers";
//替换为
const std::string authorName("Scott Meyers");

3. #define没有作用域,不能将常量的作用域限制在class内;

class GamePlayer {
private:
    static const int NumTurns = 5; // 常量声明
    int scores[NumTurns];          // 使用该常量
}

4. 如果上述类中,编译器不允许在类中设定初值,可以改用枚举值替代;

5. enum 和 #define定义的对象不会导致非必要的内存分配;

class GamePlayer {
private:
    enum { NumTurns = 5 }; // NumTurns 成为5的记号名称
    int scores[NumTurns];  
}
  • enum 行为类似#define,而不像const,因为对const对象取地址是合法的,对前面两个定义的对象取地址是不合法的;
  • 在C++中,enum类型的取值通常被编译器实现为整数(右值),对右值取地址是非法的;
  • 它们的值被编译器直接嵌入到生成的机器码中,不会在栈上开辟空间,没有内存分配的过程。

6. 形似函数的宏,最好用inline函数替换

  • 宏定义避免了函数调用的开销
  • 但是存在行为不可预料以及类型安全等问题
#define CALL_WITH_MAX(a, b) f((a) > (b) ? (a) : (b))
int a = 5, b = 0;
CALL_WITH_MAX(++a, b);    // a被累加两次
CALL_WITH_MAX(++a, b+10); // a被累加一次

// 替换为
template<typename T>
inline void callWithMax(const T& a, const T& b) { 
    f(a > b ? a : b);
}

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

背景:读取初始化的值会导致不明确的行为,因此使用对象之前首先需要初始化文章来源地址https://www.toymoban.com/news/detail-809769.html

  • 内置类型:手动初始化
  • 自定义类型:由构造函数来进行初始化;
    • 成员变量的初始化动作发生在进入构造函数本体之前;
    • 初始化列表调用一次拷贝构造函数,效率比先调用默认构造函数再调用拷贝赋值效率高;
    • 如果成员变量是const或者引用类型,一定要赋初值,不能被赋值;
    • 成员变量的初始化顺序:
      • 父类成员初始化优先于子类
      • 以成员变量声明的次序被初始化(不是在初始化列表的顺序)
      • 如果成员变量声明由依赖关系,注意先后顺序
class PhoneNumber {};
class ABEntry {
public:
    // 初始化列表效率更高
    ABEntry(const std::string& name, const std::string& address, const std::list<PhoneNumber>& phones):
        theName(name), 
        theAddress(address), 
        thePhones(phones), 
        numTimesConsulted(0) {}
private:
    std::string theName;
    std::string theAddress;
    std::list<PhoneNumber> thePhones;
    int numTimesConsulted;
    const int test;
};
// 赋值,首先调用默认构造函数为变量设初值,然后立刻赋予新值
// ABEntry::ABEntry(const std::string& name, const std::string& address, const std::list<PhoneNumber>& phones) {
//     theName = name;
//     theAddress = address;
//     thePhones = phones;
//     numTimesConsulted = 0;
// }

int main() {
    int x = 0;
    const char* text = "A C-style string";
    double d;
    std::cin >> d;
    return 0;
}

/*
 * const成员变量没有初始化
item_04.h: In constructor ‘ABEntry::ABEntry(const string&, const string&, const std::__cxx11::list<PhoneNumber>&)’:
item_04.h:10:5: error: uninitialized const member in ‘const int’ [-fpermissive]
   10 |     ABEntry(const std::string& name, const std::string& address, const std::list<PhoneNumber>& phones):
      |     ^~~~~~~
item_04.h:20:15: note: ‘const int ABEntry::test’ should be initialized
   20 |     const int test;
*/
  • non-local-static对象
    • 包括:global对象、namespace作用域内对象、类内、file作用域内
    • 定义于不同的编译单元内的non-local-static对象初始化顺序无明确定义
      • 考虑以下场景,两个不同文件中变量,需要确保tfs被使用前被初始化;
      • 解决方法是声明一个专属函数,然后返回一个静态引用
        • 函数被调用期间,首次遇到该定义时初始化;
        • 如果不被调用就不会引发构造和析构的成本;
        • 多线程环境下需要在主线程启动前手动调用reference-returning函数
class FileSystem {
public:
    std::size_t numDisks() const;
};
FileSystem& tfs() {
    static FileSystem fs;
    return fs;
}

class Directory {
public:
    Directory();
}
Directory::Directory() {
    std::size_t disks = tfs.numDisks();
}
Directory& tempDir() {
    static Directory td;
    return td;
}

到了这里,关于【Effective C++】让自己习惯C++的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • effective c++ 笔记

    TODO:还没看太懂的篇章 item25 item35 模板相关内容 可以将C++视为以下4种次语言的结合体: C 面向对象 模板 STL 每个次语言都有自己的规范,因此当从其中一个切换到另一个时,一些习惯或守则是可能会发生变化的。 用const替换#define有以下2个原因: #define定义的符号名称可能没

    2024年02月10日
    浏览(28)
  • C++笔记-effective stl

    熟悉stl本身 慎重选择stl容器,每一种stl容器对应不同的使用场景,比如deque往往比vector更加合适 封装stl容器,积极的使用stl,可以高效的使用它 积极使用其对应迭代器使用的函数,比如做相加运算使用accumulate替代for循环,可以更加高效 调用对应的函数的时候,不使用过于复

    2024年01月18日
    浏览(41)
  • 【Effective C++】4. 设计与声明

    如何创建和销毁 初始化对象和对象的赋值应该有什么差别 以值传递意味着什么 新type的合法值 继承体系 类型转换 操作符重载 继承标准 未声明接口 type一般化(template) 有以下几个优势: 1. 语法一致性:访问class成员时每一个都是函数,不需要记住是否需要小括号 2. 使成员

    2024年01月24日
    浏览(37)
  • effective c++ 笔记 条款18-25

    使用外覆类型(wrapper)提醒调用者传参错误检查,将参数的附加条件限制在类型本身 三个参数类型相同的函数容易造成误用 导入新的类型 限制取值 从语法层面限制调用者不能做的事 operate*的返回类型上加上const修饰,防止无意的错误赋值if (a * b = c) 接口应表现出与内置类型

    2024年02月21日
    浏览(42)
  • 个人Django项目的创建流程,个人开发习惯

    1、django-admin startproject djangoDemo 2、python manage.py startapp app01 3、注册app:app01.apps.App01Config 4、数据库连接配置(需要安装mysqlclient): 5、在app01下的models.py里创建表结构 6、执行生成表结构的命令 python manage.py makemigrations python manage.py migrate 7、在urls.py中导入app01.views 并添加添加

    2023年04月08日
    浏览(44)
  • More Effective C++学习笔记(1)

    在任何情况下都 不能使用指向空值的引用 。一个引用必须总是指向某个对象,必须有初值。 如果变量指向 可修改,且有可能指向null ,就把变量设为 指针 ;如果变量 总是必须代表一个对象(不可能为null) ,就把变量设为 引用 。 引用可能比指针更高效 ,因为不必像指针

    2024年02月12日
    浏览(54)
  • effective c++ 20 传引用代替传值

    本节,作者开始讨论引用。我们知道c语言已经有了指针,通过指针我们也就可以修改变量本身,而不是修改变量的副本(传值), 那么在c++中又搞出来个引用, 那么其是不是有点重复? 我们知道在函数的传参中,如果传递的是指针, 那么就不可避免的要进行取地址和解引

    2024年02月05日
    浏览(43)
  • (自己动手开发自己的语言练手级应用)JSON(JavaScript Object Notation) 产生式(BNF)

     写自己的开发语言时,很多人都会拿JSON当第一个练习对象 开源net json FJSON 解析工具 https://dbrwe.blog.csdn.net/article/details/107611540?spm=1001.2014.3001.5502 以上是JSON的简化产生式表示形式。其中, json 是最顶层的规则,可以是一个对象或一个数组。 object 表示一个对象,由一对大括号

    2024年02月10日
    浏览(50)
  • 《Effective C++中文版,第三版》读书笔记7

    隐式接口: ​ 仅仅由一组有效表达式构成,表达式自身可能看起来很复杂,但它们要求的约束条件一般而言相当直接而明确。 显式接口: ​ 通常由函数的签名式(也就是函数名称、参数类型、返回类型)构成 ​ 在源码中明确可见。 编译期多态: 在编译时才能确定具体调

    2024年02月09日
    浏览(35)
  • 《More Effective C++》《基础议题——2、尽量使用C++类型的风格转换》

    类型转换是一般程序员所不能忍受的,但是在紧要关头,类型转换是必须的。C风格的类型转换太过简单,粗暴,不能进行精确的类型转换;为了弥补C转换上功能的不足,C++提供了四种常用的类型转换来应付复杂的转换需求。 static_cast用于在编译时执行类型转换,主要用于相

    2024年01月18日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包