<Effective C++>读书摘要--Designs and Declarations<二>
<Item 20> Prefer pass-by-reference-to-const to pass-by-value
1、By default, C++ passes objects to and from functions by value (a characteristic it inherits from C). Unless you specify otherwise, function parameters are initialized with copies of the actual arguments, and function callers get back a copy of the value returned by the function. These copies are produced by the objects' copy constructors. This can make pass-by-value an expensive operation. 使用传值调用函数的时候,还需要创建和析构参数的父类和参数类中的非静态成员变量。Still, it would be nice if there were a way to bypass all those constructions and destructions. There is: pass by reference-to-const:使用const保证不修改入参的值。
bool validateStudent(const Student& s);
2、Copy-On-Write(COW)的一个定义:在复制一个对象的时候并不是真正的把原先的对象复制到内存的另外一个位置上,而是在新对象的内存映射表中设置一个指针,指向源对象的位置,并把那块内存的Copy-On-Write位设置为1.在对这个对象执行读操作的时候,内存数据没有变动,直接执行就可以。在写的时候,才真正将原始对象复制一份到新的地址,修改新对象的内存映射表到这个新的位置,然后往这里写。如C++里面一些种类的string实现。
3、Passing parameters by reference also avoids the slicing problem. When a derived class object is passed (by value) as a base class object, the base class copy constructor is called, and the specialized features that make the object behave like a derived class object are "sliced" off. You're left with a simple base class object — little surprise, since a base class constructor created it. This is almost never what you want.
4、If you peek under the hood of a C++ compiler, you'll find that references are typically implemented as pointers, so passing something by reference usually means really passing a pointer.Implementers of iterators and function objects are responsible for seeing to it that they are efficient to copy and are not subject to the slicing problem. (This is an example of how the rules change, depending on the part of C++ you are using — see Item 1.)
5、Built-in types are small, so some people conclude that all small types are good candidates for pass-by-value, even if they're user-defined. This is shaky reasoning. Just because an object is small doesn't mean that calling its copy constructor is inexpensive. Many objects — most STL containers among them — contain little more than a pointer, but copying such objects entails copying everything they point to. That can be very expensive.
Even when small objects have inexpensive copy constructors, there can be performance issues. Some compilers treat built-in and user-defined types differently, even if they have the same underlying representation. For example, some compilers refuse to put objects consisting of only a double into a register, even though they happily place naked doubles there on a regular basis. When that kind of thing happens, you can be better off passing such objects by reference, because compilers will certainly put pointers (the implementation of references) into registers.
Another reason why small user-defined types are not necessarily good pass-by-value candidates is that, being user-defined, their size is subject to change. A type that's small now may be bigger in a future release, because its internal implementation may change. Things can even change when you switch to a different C++ implementation. As I write this, for example, some implementations of the standard library's string type are seven times as big as others.
6、In general, the only types for which you can reasonably assume that pass-by-value is inexpensive are built-in types and STL iterator and function object types. For everything else, follow the advice of this Item and prefer pass-by-reference-to-const over pass-by-value.
7、Things to Remember
Prefer pass-by-reference-to-const over pass-by-value. It's typically more efficient and it avoids the slicing problem.
The rule doesn't apply to built-in types and STL iterator and function object types. For them, pass-by-value is usually appropriate.
<Item 21>Don't try to return a reference when you must return an object
8、C++中的引用类型对应指针类型,只是增加了编译期约束:一旦引用了一个对象则不能更换。
9、A function can create a new object in only two ways: on the stack(栈) or on the heap(堆). Creation on the stack is accomplished by defining a local variable.
10、返回不同类型变量的引用都可能会存在问题
- The fact is, any function returning a reference to a local object is broken. (The same is true for any function returning a pointer to a local object.)。对返回的局部变量的引用或者指针进行对象操作时未定义行为。因此返回stack上面的对象上面的引用是不可行的
- 通过new使重载的操作符返回heap上面的变量可能会造成内存泄露
const Rational& operator*(const Rational& lhs, // warning! more bad
const Rational& rhs) // code!
{
Rational *result = new Rational(lhs.n * rhs.n, lhs.d * rhs.d);
return *result;
}
Rational w, x, y, z;
w = x * y * z; // same as operator*(operator*(x, y), z) 没有delete内存泄漏
- Like all designs employing the use of static objects, this one immediately raises our thread-safety hackles, but that's its more obvious weakness. To see its deeper flaw, consider this perfectly reasonable client code:static对象会让编译器产生一段惰性初始化代码,使得代码多了一个条件分支,影响局部性能。
const Rational& operator*(const Rational& lhs, // warning! yet more
const Rational& rhs) // bad code!
{
static Rational result; // static object to which a
// reference will be returned
result = ... ; // multiply lhs by rhs and put the
// product inside result
return result;
}
Rational a, b, c, d;
...
if ((a * b) == (c * d)) { //条件判断不符合预期
do whatever's appropriate when the products are equal;
} else {
do whatever's appropriate when they're not;
}
11、The right way to write a function that must return a new object is to have that function return a new object. For Rational's operator*, that means either the following code or something essentially equivalent:
inline const Rational operator*(const Rational& lhs, const Rational& rhs)
{
return Rational(lhs.n * rhs.n, lhs.d * rhs.d);
}
Like all programming languages, C++ allows compiler implementers to apply optimizations to improve the performance of the generated code without changing its observable behavior, and it turns out that in some cases, construction and destruction of operator*'s return value can be safely eliminated. It all boils down to this: when deciding between returning a reference and returning an object, your job is to make the choice that offers correct behavior. Let your compiler vendors wrestle with figuring out how to make that choice as inexpensive as possible.
12、Things to Remember
Never return a pointer or reference to a local stack object, a reference to a heap-allocated object, or a pointer or reference to a local static object if there is a chance that more than one such object will be needed. (Item 4 provides an example of a design where returning a reference to a local static is reasonable, at least in single-threaded environments.)
<Effective C++>读书摘要--Designs and Declarations<二>的更多相关文章
- <Effective C++>读书摘要--Designs and Declarations<三>
<Item 22> Declare data members private 1.使数据成员private,保持了语法的一致性,client不会为访问一个数据成员是否需要使用括号进行函数调 ...
- <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++>读书摘要--Implementations<二>
<Item29> Strive for exception-safe code. 1.如下面的代码 class PrettyMenu { public: ... void changeBa ...
- <Effective C++>读书摘要--Inheritance and Object-Oriented Design<二>
<Item 36> Never redefine an inherited non-virtual function 1.如下代码通过不同指针调用同一个对象的同一个函数会产生不同的行为Th ...
- <Effective C++>读书摘要--Resource Management<二>
<Item 15> Provide access to raw resources in resource-managing classes 1.You need a way to con ...
- <Effective C++>读书摘要--Ctors、Dtors and Assignment Operators<二>
<Item 9> Never call virtual functions during construction or destruction 1.you shouldn't call ...
- <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<一>
1.Furthermore, I explain what the different features in C++ really mean — what you are really expres ...
- <Effective C++>读书摘要--Implementations<一>
1.For the most part, coming up with appropriate definitions for your classes (and class templates) a ...
随机推荐
- 剑指Offer-迭代
1.大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0) 备注:斐波那契数列指的是这样一个数列从第3项开始,每一项都等于前两项之和. public st ...
- 模拟MBR Grub故障修复
1. MBR故障修复 备份 mkdir /pp mount /dev/sdb1 /pp dd if=/dev/sda of=/pp/mrb.bak bs=512 count=1 破坏mrb dd ...
- xp sp3安装.Net 4.0提示严重错误,0x80070643,解决办法2017版
客户电脑上要装金税开票软件,需要.net 4.0.30319.1,电脑环境是xp sp3,已经安装了.net 2, .net 3.5sp1,安装.net 4.0的时候提示错误0x80070643 因为 ...
- day 13 内置函数
内置函数思维导图:https://www.processon.com/view/link/5c13ad2de4b0ed122da75668 内置函数 作用域相关: locals() 返回当前作用域 ...
- Flink实例-Wordcount详细步骤
link实例之Wordcount详细步骤 1.我的IDE是IntelliJ IDEA.在官网上https://www.jetbrains.com/idea/下载最新版2018.2的IDEA,如下图.破 ...
- 搭建Jupyter Notebook服务器
昨天发了Jupyter的使用,补一篇Jupyter服务器的搭建~ 一.搭建Jupyter 1.安装 使用virtualenv建虚拟环境.在虚拟环境中安装jupyter.matplotlib等等需要的库 ...
- go内建容器-字符和字符串操作
1.基础定义 在基础语法篇提到过golang的rune相当于其他编程语言的char,其本质是一个int32(四字节),用[]rune来转换一个字符串时,得到的是个解码后的结果,存储在新开辟的[]run ...
- 前端必备的Nginx学习
由于机缘巧合,认识了一些朋友,给我介绍了搬瓦工的网站.买了一个国外的服务器,既可以FQ又拥有了一个搭载 Centos 6 的服务器.一年19.99美元,折合人民币也就130左右,一键搭建.有兴趣可以点 ...
- sublime_text3常用操作与快捷键
1.编辑多列 按鼠标滚轮进行多列选中 键盘ctrl+alt+↓进行多行选中操作 2.快捷键 ctrl+H:替换(F为经典的搜索) ctrl+G:跳到指定行 ctrl+D:选词,连续按选中下面匹配的词, ...
- 20154327 Exp1 PC平台逆向破解
一.实践目标 1.运行原本不可访问的代码片段 2.强行修改程序执行流 3.以及注入运行任意代码 二.基础知识 1.直接修改程序机器指令,改变程序执行流程 2.通过构造输入参数,造成BOF攻击,改变程序 ...