<Effective C++>读书摘要--Accustoming Youself to C++
<Item 1>View C++ as a federation of languages。
1、把C++看成4种子语言组成,即C、Object-Oriented C++、Template C++、The STL。
2、Things to Remember:Rules for effective C++ programming vary, depending on the part of C++ you are using.
因为C++有很多的编程范式,在项目开发过程中,明确规范怎么使用C++很重要,这样可以使整个团队尽量使用一样的风格,并把项目一直做下去
<Item 2>Prefer consts, enums, and inlines to #defines。
3、prefer the compiler to the preprocessor。因为宏定义不会被编译到符号表里面去,因此会对问题的调试定位带来麻烦,同时宏定义不能进行面向对象的封装和私有化。
4、使用常量代替宏定义的时候需要注意两个点,
一个是定义指针常量的时候需要使用两个const,如
const char * const authorName = "Scott Meyers";
其中前一个const修饰char,后一个const修饰指针,可以逆着读authorName 是一个const指针,指向const的char常量
另一个是使用class-specific constant的时候,为了保持一个内存copy,需要使用static进行定义
class GamePlayer {
private:
static const int NumTurns = ; // constant declaration
int scores[NumTurns]; // use of constant
...
};
What you see above is a declaration for NumTurns, not a definition. Usually, C++ requires that you provide a definition for anything you use, but class-specific constants that are static and of integral type (e.g., integers, char s, bool s) are an exception. As long as you don't take their address, you can declare them and use them without providing a definition. If you do take the address of a class constant, or if your compiler incorrectly insists on a definition even if you don't take the address, you provide a separate definition like this:
const int GamePlayer::NumTurns; // definition of NumTurns; see // below for why no value is given
Because the initial value of class constants is provided where the constant is declared (e.g., NumTurns is initialized to 5 when it is declared), no initial value is permitted at the point of definition.(也可以声明的时候不给初值,而在定义的时候给初值)
Note, by the way, that there's no way to create a class-specific constant using a #define, because #define s don't respect scope.
5、the enum hack
class GamePlayer {
private:
enum { NumTurns = }; // "the enum hack" — makes
// NumTurns a symbolic name for 5
int scores[NumTurns]; // fine
...
};
First, the enum hack behaves in some ways more like a #define than a const does, and sometimes that's what you want. For example, it's legal to take the address of a const, but it's not legal to take the address of an enum, and it's typically not legal to take the address of a #define, either. If you don't want to let people get a pointer or reference to one of your integral constants, an enum is a good way to enforce that constraint.
A second reason to know about the enum hack is purely pragmatic. Lots of code employs it, so you need to recognize it when you see it. In fact, the enum hack is a fundamental technique of template metaprogramming
6、another common (mis)use of the #define directive is using it to implement macros that look like functions but that don't incur the overhead of a function call.
// call f with the maximum of a and b #define CALL_WITH_MAX(a, b) f((a) > (b) ? (a) : (b))
替换为
template<typename T> // because we don't
inline void callWithMax(const T&a,const T&b)// know what T is, we
{ // pass by reference-to-
f(a > b ? a : b); // const — see Item 20
}
7、Given the availability of const s, enum s, and inline s, your need for the preprocessor (especially #define) is reduced, but it's not eliminated. #include remains essential, and #ifdef /#ifndef continue to play important roles in controlling compilation. It's not yet time to retire the preprocessor, but you should definitely give it long and frequent vacations.
8、Things to Remember:
For simple constants, prefer const objects or enums to #define s.
For function-like macros, prefer inline functions to #define s.
<Item 3>Use const whenever possible。
9、const施加了一个semantic constraint,并有编译器来保证,同时It allows you to communicate to both compilers and other programmers that a value should remain invariant.
10、下面两种语法格式含义一致都表示Widget 为const常量
void f1(const Widget *pw); // f1 takes a pointer to a
// constant Widget object
void f2(Widget const *pw); // so does f2
11、If you want an iterator that points to something that can't be modified (i.e., the STL analogue of a const T* pointer), you want a const_iterator :
std::vector<int> vec;
...
const std::vector<int>::iterator iter = // iter acts like a T* const
vec.begin();
*iter = ; // OK, changes what iter points to
++iter; // error! iter is const
std::vector<int>::const_iterator cIter = //cIter acts like a const T*
vec.begin();
*cIter = ; // error! *cIter is const
++cIter; // fine, changes cIter
12、Having a function return a constant value often makes it possible to reduce the incidence of client errors without giving up safety or efficiency.
class Rational {... };
const Rational operator*(const Rational& lhs, const Rational& rhs);
Rational a, b, c;
...
(a * b) = c; // invoke operator= on the
// result of a*b!
if (a * b = c)... // oops, meant to do a comparison!
13、The purpose of const on member functions is to identify which member functions may be invoked on const objects. Such member functions are important for two reasons. First, they make the interface of a class easier to understand. It's important to know which functions may modify an object and which may not. Second, they make it possible to work with const objects. That's a critical aspect of writing efficient code, because, as Item 20 explains, one of the fundamental ways to improve a C++ program's performance is to pass objects by reference-to-const. That technique is viable only if there are const member functions with which to manipulate the resulting const -qualified objects.
14、Many people overlook the fact that member functions differing only in their constness can be overloaded, but this is an important feature of C++.const objects most often arise in real programs as a result of being passed by pointer- or reference-to-const.
15、What does it mean for a member function to be const ? There are two prevailing notions: bitwise constness (also known as physical constness) and logical constness.The bitwise const camp believes that a member function is const if and only if it doesn't modify any of the object's data members (excluding those that are static), i.e., if it doesn't modify any of the bits inside the object.In fact, bitwise constness is C++'s definition of constness, and a const member function isn't allowed to modify any of the non-static data members of the object on which it is invoked.(对象中包含指针的时候,指针不变但是指针指向的数据可变)。Adherents to this philosophy argue that a const member function might modify some of the bits in the object on which it's invoked, but only in ways that clients cannot detect.mutable frees non-static data members from the constraints of bitwise constness:
class CTextBlock {
public:
...
std::size_t length() const;
private:
char *pText;
mutable std::size_t textLength; // these data members may
mutable bool lengthIsValid; // always be modified, even in
}; // const member functions
std::size_t CTextBlock::length() const
{
if (!lengthIsValid) {
textLength = std::strlen(pText); // now fine
lengthIsValid = true; // also fine
}
return textLength;
}
16、Avoiding Duplication in const and Non-const Member Functions
class TextBlock {
public:
...
const char& operator[](std::size_t position) const // same as before
{
...
...
...
return text[position];
}
char& operator[](std::size_t position) // now just calls const op[]
{
return const_cast<char&>( // cast away const on
// op[]'s return type;
static_cast<const TextBlock&>(*this) // add const to *this's type;
[position] // call const version of op[]
);
}
...
};
16、Things to Remember
Declaring something const helps compilers detect usage errors. const can be applied to objects at any scope, to function parameters and return types, and to member functions as a whole.
Compilers enforce bitwise constness, but you should program using conceptual constness.
When const and non-const member functions have essentially identical implementations, code duplication can be avoided by having the non-const version call the const version.
<Item 4> Make sure that objects are initialized before they're used
17、The rules of C++ stipulate that data members of an object are initialized before the body of a constructor is entered.参数初始化列表才是真实的初始化过程,构造函数内部的赋值不是初始化。For objects of built-in type like numTimesConsulted, there is no difference in cost between initialization and assignment, but for consistency, it's often best to initialize everything via member initialization.
18、Sometimes the initialization list must be used, even for built-in types. For example, data members that are const or are references must be initialized; they can't be assigned
19、当有很多成员或者基类需要初始化的时候,it's not unreasonable to omit entries in the lists for data members where assignment works as well as true initialization, moving the assignments to a single (typically private) function that all the constructors call.
20、One aspect of C++ that isn't fickle is the order in which an object's data is initialized. This order is always the same: base classes are initialized before derived classes (see also Item 12), and within a class, data members are initialized in the order in which they are declared. 成员初始化的顺序和初始化列表中的顺序无关,但是建议初始化列表中的数据和声明的顺序一致,以免读者误解
21、A static object is one that exists from the time it's constructed until the end of the program. Stack and heap-based objects are thus excluded. Included are global objects, objects defined at namespace scope, objects declared static inside classes, objects declared static inside functions, and objects declared static at file scope. Static objects inside functions are known as local static objects (because they're local to a function), and the other kinds of static objects are known as non-local static objects. Static objects are automatically destroyed when the program exits, i.e., their destructors are automatically called when main finishes executing.
22、A translation unit is the source code giving rise to a single object file. It's basically a single source file, plus all of its #include files.
23、The problem we're concerned with, then, involves at least two separately compiled source files, each of which contains at least one non-local static object (i.e., an object that's global, at namespace scope, or static in a class or at file scope). And the actual problem is this: if initialization of a non-local static object in one translation unit uses a non-local static object in a different translation unit, the object it uses could be uninitialized, because the relative order of initialization of non-local static objects defined in different translation units is undefined.解决方案是使用函数封装static变量确保初始化。This approach is founded on C++'s guarantee that local static objects are initialized when the object's definition is first encountered during a call to that function.
class FileSystem { ... }; // as before
FileSystem& tfs() // this replaces the tfs object; it could be
{ // static in the FileSystem class
static FileSystem fs; // define and initialize a local static object
return fs; // return a reference to it
}
class Directory { ... }; // as before
Directory::Directory( params ) // as before, except references to tfs are
{ // now to tfs()
...
std::size_t disks = tfs().numDisks(); //使用函数封装确保初始化
...
}
Directory& tempDir() // this replaces the tempDir object; it
{ // could be static in the Directory class
static Directory td; // define/initialize local static object
return td; // return reference to it
}
24、On the other hand, the fact that these functions contain static objects makes them problematic in multithreaded systems. Then again, any kind of non-const static object — local or non-local — is trouble waiting to happen in the presence of multiple threads. One way to deal with such trouble is to manually invoke all the reference-returning functions during the single-threaded startup portion of the program. This eliminates initialization-related race conditions.
25、Things to Remember
Manually initialize objects of built-in type, because C++ only sometimes initializes them itself.
In a constructor, prefer use of the member initialization list to assignment inside the body of the constructor. List data members in the initialization list in the same order they're declared in the class.
Avoid initialization order problems across translation units by replacing non-local static objects with local static objects.
<Effective C++>读书摘要--Accustoming Youself to C++的更多相关文章
- <Effective C++>读书摘要--Implementations<二>
<Item29> Strive for exception-safe code. 1.如下面的代码 class PrettyMenu { public: ... void changeBa ...
- <Effective C++>读书摘要--Implementations<一>
1.For the most part, coming up with appropriate definitions for your classes (and class templates) a ...
- <Effective C++>读书摘要--Designs and Declarations<一>
<Item 18> Make interfaces easy to use correctly and hard to use incorrectly 1.That being the c ...
- <Effective C++>读书摘要--Introduction
Introduction 1.Learning the fundamentals of a programming language is one thing; learning how to des ...
- <Effective C++>读书摘要--Templates and Generic Programming<一>
1.The initial motivation for C++ templates was straightforward: to make it possible to create type-s ...
- <Effective C++>读书摘要--Inheritance and Object-Oriented Design<二>
<Item 36> Never redefine an inherited non-virtual function 1.如下代码通过不同指针调用同一个对象的同一个函数会产生不同的行为Th ...
- <Effective C++>读书摘要--Inheritance and Object-Oriented Design<一>
1.Furthermore, I explain what the different features in C++ really mean — what you are really expres ...
- <Effective C++>读书摘要--Designs and Declarations<三>
<Item 22> Declare data members private 1.使数据成员private,保持了语法的一致性,client不会为访问一个数据成员是否需要使用括号进行函数调 ...
- <Effective C++>读书摘要--Designs and Declarations<二>
<Item 20> Prefer pass-by-reference-to-const to pass-by-value 1.By default, C++ passes objects ...
随机推荐
- Git 学习笔记–基本操作
Git 与 SVN 不同,是分布式的版本控制系统,不需要主服务器即可工作,实际中为了方便各个工作者间同步工作,通常还是会设置主服务器. Git的设置及初始化: 设置全局用户信息: luojiahu@u ...
- 将图片绘制到画布上:imagecopy()
<?php //1. 绘制图像资源(创建一个画布) $image = imagecreatetruecolor(500, 300); //2. 先分配一个绿色 $green = imagecol ...
- mysql的length与char_length的区别
length: 是计算字段的长度一个汉字是算三个字符,一个数字或字母算一个字符 char_length:不管汉字还是数字或者是字母都算是一个字符 同时这两个函数,可用于判断数据中是否有中文文字 例 ...
- 【C】三目运算符(先是问号之后又是冒号的那个)
// 看这个例子就可以懂了 a = b == c ? d : e ; //如果 b==c,执行 a=d //否则执行 a=e //为了方便阅读,也可以改成下方代码 a = (b == c) ? d : ...
- MFC非模态添加进程控件方法二(自定义消息方法)
以下内容有大部分转载自CSDN,经过自己整理完成. 该文主要的方法为在非模态对话框中自定义一组消息函数,然后在主窗口中开辟一个线程通过线程把消息传递给子窗口进行更新. 在子窗口类中定义消息如下: /* ...
- Django的安装创建与连接数据库
HTTP协议简介 HTTP是一个客户端终端(用户)和服务器端(网站)请求和应答的标准(TCP).通过使用网 页浏览器.网络爬虫或者其它的工具,客户端发起一个HTTP请求到服务器上指定端口(默认端 口为 ...
- VXLAN简介(摘抄)
VXLAN简介 VXLAN:Virtual eXtensible Local Area Network的缩写,虚拟扩展局域网,现代数据中心的的一种网络虚拟化技术,即在传统的三层IP网络上虚拟出一张二层 ...
- VMWare虚拟机的网络类型配置选择详解
VMWare虚拟机网络有三种类型,当然还有最后一种类型就是“不使用网络连接”,哈哈....... VMWare在安装会有让选择网络类型的选项,如果不确认使用那一种网络类型,也可以先随便选择一种网络类型 ...
- Java语言简介
Java即计算机编程语言 1.概念 Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承.指针等概念,因此Java语言具有功能强大和简单易用两个特征.Jav ...
- springboot之websocket
一.WebSocket协议是基于TCP的一种新的网络协议.它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端. 二.长久以来, 创建实现客户端和用户端之间双工 ...