Effective C++ 学习笔记一:让自己习惯cpp

一:View C++ as a federation of languages;   视C++为一个语言联邦

将c++视为由相关语言组成的联邦而非单一语言。理解其相关的次语言。

1.C

2.object-oriented C++

3.Template C++

4.STL

c++高效编程守则视情况而变化,取决于你使用C++的哪一部分

二:Prefer consts,enums,and inlines to #defines  尽量以const, enum, inline 替换 #define

即 宁可以编译器代替预处理器。

#define ASPECT_RATIO 1.653

扫描二维码关注公众号,回复: 9536929 查看本文章

宏定义中的记号名称没有被写入记号表,如果由关于此的编译错误时不会提到该记号。

以常量替换上述的宏

const double AspectRatio = 1.653;:好处 使用常量可能比使用#define导致较小量的代码

注:定义常量指针

const char* const authorName = "Scott Meyers";

使用const std::string authorNmae("Scott Meyers");更好些

类常量 为了将此常量限制在类内并且确保此常量至多只有一份实体,必须声明成一个静态成员常量。

注:enum hack

1.取址一个enum不合法,如果不想让别人获得一个指针或者引用指向某个整数常量,enum可以完成这个约束。enums也不会导致非必要的内存分配。

2.enum hack是模板元编程的基础技术

注:用模板内联函数代替宏定义函数

总结:对于单纯常量,以const或者enums替换#defines

          对于形似函数的宏,以inline函数替换#defines

三:Use const whenever possible 尽可能使用const

const如果出現在星号左边,表示被指物是常量,如果出现在星号右边,表示指针自身是常量。

对于迭代器,类似T*指针。

声明迭代器为const表明该迭代器不得指向不同的东西,但它所指向的东西的值是可以改动的。

如果希望迭代器所指的东西不可改动,需要const_iterator (STL模拟一个const T*指针)。

例子:

	std::vector<int> vec;

	const std::vector<int>::iterator iter = vec.begin();
	*iter = 10;
	++iter;//error

	std::vector<int>::const_iterator cIter = vec.begin();
	*cIter = 10;//error
	++cIter;

对于函数,const返回值,参数等会避免一些无意义的赋值错误。

const 成员函数:

两个成员函数如果只是常量性不同,可以被重载。

例子:

class TextBlock
{
public:
	const char& operator[](std::size_t position) const {
		return text[position];
	}
	char& operator[](std::size_t position)
	{
		return text[position];
	}
private:
	std::string text;
};
class CTextBlock
{
public:
	char& operator[](std::size_t position) const {
		return pText[position];
	}
private:
	char* pText;
};

const CTextBlock cctb("Hello");
char* pc = &cctb[0];
*pc = 'J';

这样虽然调用了const成员函数 也可以改变类的一些bit;

注:可以利用mutable关键字 释放掉non-static成员变量的bitwise constness约束

使得const成员函数也可以修改被mutable修饰的变量。

注:在const和non-const成员函数中避免重复

利用转型去掉重复代码:

class TextBlock
{
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 TextBlock&>(*this)[position]);
	}
private:
	std::string text;
};

与此相反,const成员函数调用non-const成员函数是一种错误行为。

总结:
将某些东西声明为const可帮助编译器侦测出错误用法。const可被施加于任何作用域内的对象,函数参数,函数返回类型,成员函数本体。

编译器强制实施bitwise constness,但你编写程序时应该使用概念上的常量性。

当const和non-const成员函数有着实质等价的实现时,令non-const版本调用const版本可避免代码重复。

四:Make sure that objects are initialized before they're used. 确定对象被使用前已先被初始化。

永远在使用对象之前先将它初始化。

1.内置类型 手工初始化 略

2.非内置类型,初始化责任落在构造函数身上,确保每一个构造函数都将对象的每一个成员初始化。

注意赋值和初始化的区别,c++规定对象的成员变量的初始化动作发生在进入构造函数本体之前。

可以使用参数列表的方式初始化,代替构造函数赋值的操作。(通常效率更高)

如果成员变量是const或references就一定需要初值,不能被赋值。所以可以总使用成员初始列表减少复杂度。

c++有着十分固定的成员初始化次序。基类早于派生类,在成员初始化列表中的顺序决定被初始化的顺序。

3.不同编译单元内定义的non-local static对象

static对象包括global对象,定义于namespace作用域内的对象,在classes内,在函数内,以及在file作用域内被声明为static的对象。

函数内的static对象称为local static对象,其他static对象称为non-local static对象。

c++对“定义于不同编译单元内的non-local static对象”的初始化次序并无明确定义。

注:trick 将每个non-local static对象搬到自己的专属函数内(该对象在此对象内被声明为static)。这些函数返回一个引用指向它所含的对象。

non-local static对象被local static对象替换了,c++保证函数内的local static对象会在该函数被调用期间,首次遇到该对象定义式时被初始化。

好处,可以确定顺序,不调用时不会被构造或者析构。

总结:

为内置型对象进行手工初始化,因为c++不保证初始化它们。

构造函数最好使用成员初值列,而不要在构造函数本体内使用赋值操作。初值列列出的成员变量,其排列次序应该和它们在class中的声明次序相同。

为免除“跨编译单元初始化次序”问题,以local static对象替换non-local static对象。

发布了35 篇原创文章 · 获赞 5 · 访问量 415

猜你喜欢

转载自blog.csdn.net/qq_33776188/article/details/103033839