【Effective C++】1. 让自己习惯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 确定对象被使用前已被初始化

背景:读取初始化的值会导致不明确的行为,因此使用对象之前首先需要初始化

  • 内置类型:手动初始化
  • 自定义类型:由构造函数来进行初始化;
    • 成员变量的初始化动作发生在进入构造函数本体之前;
    • 初始化列表调用一次拷贝构造函数,效率比先调用默认构造函数再调用拷贝赋值效率高;
    • 如果成员变量是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;
}

  • 27
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 《Effective C++ 中文版》是由Scott Meyers所编写的一本关于C++编程的指南。它不仅是C++编程者的必备书籍,也是所有编程人员的经典读物。本书在讲解C++编程过程中,给出了许多实用的技巧和建议,帮助程序员更好地使用C++编写高效、可靠的程序。 本书共包含50个条款,每个条款都包含一个具有实际意义的问题和解决方案。这些解决方案是作者多年编写C++代码的经验总结,结合了C++的最佳实践,旨在帮助读者更好地理解C++语言特性和语言使用习惯。这些技巧从简单到复杂,由浅入深地介绍了如何编写高效的C++代码。 在本书中,你将学习到: 1. 内存管理技巧。包括如何使用智能指针、如何处理内存泄漏问题等。 2. 类设计和继承技巧。包括如何设计和实现抽象基类、虚函数等。 3. 异常处理和错误处理。包括如何处理异常、如何正确使用异常、如何进行错误处理等。 4. 代码优化和调试技巧。包括如何做好代码优化、如何进行调试、如何实现高效数据结构等。 《Effective C++ 中文版》不仅适用于初学者,也适合有一定经验的C++开发人员参考。它是一本非常实用的、能帮助你更好地理解和掌握C++编程技巧的书籍。无论你是一名编程新手还是有多年经验的专业开发人员,都值得一读。 ### 回答2: 《Effective C++ 中文版》是一本关于C++编程的经典书籍。其中包含了许多有关C++编程的实用技巧,以及注意事项和最佳实践。本书的作者Scott Meyers是一位著名的C++专家,通过本书他在编程技巧和C++语言语法方面给我们提供了很多宝贵的经验。本书主要分为50个章节,每一个章节有自己的主题,涉及面非常广泛,包括了一些比较基础的C++概念,以及一些高级的编程技巧和设计模式的应用。其中一些章节是非常值得注意的,比如说有关内存管理,函数重载以及类设计等等。 通过《Effective C++ 中文版》这本书,读者可以学到很多C++编程的实用技巧,这些技巧在实际开发中非常有用。例如,书中介绍了如何正确使用函数重载,如何避免内存泄漏以及如何正确地设计类等等。此外,这本书对于大家掌握C++的语法和一些编程技巧以及习惯养成等方面也是非常有帮助的。因此,《Effective C++ 中文版》是一本非常值得阅读的C++经典之作,对于C++初学者和专业程序员都是有益的。 ### 回答3: 《Effective C》是一本关于C语言编程的实用指南,旨在帮助读者更加高效地使用C语言进行开发。本书作者为Scott Meyers,是知名的C++编程之父,在本书中他分享了自己多年来在C语言领域的经验和技巧。 本书主要分为四个部分,分别是基础知识、指针、内存管理和高级技巧。第一部分主要介绍C语言的基本语法和特性,包括编码风格、数据类型、流程控制等;第二部分则深入讲解指针的概念和用法,包括指针的语法、指针和数组、指针和函数等;第三部分主要涉及内存管理方面的知识,包括动态内存分配、内存泄漏、内存地址等;第四部分则介绍一些高级技巧,如位操作、函数指针、字符串操作等。 本书着重强调了C语言的“低级别”特性,如指针和内存管理,这正是C语言的优越之处。但同时,这些特性也是导致C语言存在一些常见问题的根源,如内存泄漏、野指针等。因此,本书特别注重这些问题的防范和解决方法,为读者提供了很多实用的技巧和建议。 总之,《Effective C》是一本非常实用和有价值的C语言编程指南。无论是新手还是经验丰富的程序员,都可以从本书中学到很多东西,提升自己的编程水平和效率。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杨主任o_o

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值