File tree 4 files changed +5
-5
lines changed
4 files changed +5
-5
lines changed Original file line number Diff line number Diff line change 2
2
3
3
** CHAPTER 2 ` auto ` **
4
4
5
- 从概念上来说,` auto ` 要多简单有多简单,但是它比看起来要微妙一些。使用它可以存储类型, 当然,它也会犯一些错误,而且比之手动声明一些复杂类型也会存在一些性能问题 。此外,从程序员的角度来说,如果按照符合规定的流程走,那` auto ` 类型推导的一些结果是错误的。当这些情况发生时,对我们来说引导` auto ` 产生正确的结果是很重要的,因为严格按照说明书上面的类型写声明虽然可行但是最好避免 。
5
+ 从概念上来说,` auto ` 要多简单有多简单,但是它比看起来要微妙一些。当然,使用它可以存储类型,但它也避免了困扰着手动声明类型的正确性和性能问题 。此外,从程序员的角度来说,如果按照符合规定的流程走,那` auto ` 类型推导的一些结果是错误的。当这些情况发生时,对我们来说引导` auto ` 产生正确的结果是很重要的,因为回到手动声明类型是一种通常最好避免的替代方法 。
6
6
7
7
本章简单的覆盖了` auto ` 的里里外外。
8
8
Original file line number Diff line number Diff line change @@ -41,7 +41,7 @@ vw.push_back(w); //把w添加进vw
41
41
42
42
这是个很严重的问题,因为老代码可能依赖于` push_back ` 提供的强烈的异常安全保证。因此,C++11版本的实现不能简单的将` push_back ` 里面的复制操作替换为移动操作,除非知晓移动操作绝不抛异常,这时复制替换为移动就是安全的,唯一的副作用就是性能得到提升。
43
43
44
- `std::vector::push_back`受益于“如果可以就移动,如果必要则复制”策略,并且它不是标准库中唯一采取该策略的函数。C++98中还有一些函数(如`std::vector::reverse `,`std::deque::insert`等)也受益于这种强异常保证。对于这个函数只有在知晓移动不抛异常的情况下用C++11的移动操作替换C++98的复制操作才是安全的。但是如何知道一个函数中的移动操作是否产生异常?答案很明显:它检查这个操作是否被声明为`noexcept`。(这个检查非常弯弯绕。像是`std::vector::push_back`之类的函数调用`std::move_if_noexcept`,这是个`std::move`的变体,根据其中类型的移动构造函数是否为`noexcept`的,视情况转换为右值或保持左值(参见[Item23](../5.RRefMovSemPerfForw/item23.md))。反过来,`std::move_if_noexcept`查阅`std::is_nothrow_move_constructible`这个*type trait*,基于移动构造函数是否有`noexcept`(或者`throw()`)的设计,编译器设置这个*type trait*的值。)
44
+ `std::vector::push_back`受益于“如果可以就移动,如果必要则复制”策略,并且它不是标准库中唯一采取该策略的函数。C++98中还有一些函数(如`std::vector::reserve `,`std::deque::insert`等)也受益于这种强异常保证。对于这个函数只有在知晓移动不抛异常的情况下用C++11的移动操作替换C++98的复制操作才是安全的。但是如何知道一个函数中的移动操作是否产生异常?答案很明显:它检查这个操作是否被声明为`noexcept`。(这个检查非常弯弯绕。像是`std::vector::push_back`之类的函数调用`std::move_if_noexcept`,这是个`std::move`的变体,根据其中类型的移动构造函数是否为`noexcept`的,视情况转换为右值或保持左值(参见[Item23](../5.RRefMovSemPerfForw/item23.md))。反过来,`std::move_if_noexcept`查阅`std::is_nothrow_move_constructible`这个*type trait*,基于移动构造函数是否有`noexcept`(或者`throw()`)的设计,编译器设置这个*type trait*的值。)
45
45
46
46
` swap ` 函数是` noexcept ` 的另一个绝佳用地。` swap ` 是STL算法实现的一个关键组件,它也常用于拷贝运算符重载中。它的广泛使用意味着对其施加不抛异常的优化是非常有价值的。有趣的是,标准库的` swap ` 是否` noexcept ` 有时依赖于用户定义的` swap ` 是否` noexcept ` 。比如,数组和` std::pair ` 的` swap ` 声明如下:
47
47
Original file line number Diff line number Diff line change @@ -83,7 +83,7 @@ private:
83
83
84
84
~~值得注意的是,因为`std::mutex`是一种只可移动类型(*move-only type*,一种可以移动但不能复制的类型),所以将`m`添加进`Polynomial`中的副作用是使`Polynomial`失去了被复制的能力。不过,它仍然可以移动。~~ (译者注:实际上 `std::mutex` 既不可移动,也不可复制。因而包含他们的类也同时是不可移动和不可复制的。)
85
85
86
- 在某些情况下,互斥量的副作用显会得过大 。例如,如果你所做的只是计算成员函数被调用了多少次,使用`std::atomic` 修饰的计数器(保证其他线程视它的操作为不可分割的整体,参见[item40](../7.TheConcurrencyAPI/item40.md))通常会是一个开销更小的方法。(然而它是否轻量取决于你使用的硬件和标准库中互斥量的实现。)以下是如何使用`std::atomic`来统计调用次数。
86
+ 在某些情况下,互斥量的副作用会显得过大 。例如,如果你所做的只是计算成员函数被调用了多少次,使用`std::atomic` 修饰的计数器(保证其他线程视它的操作为不可分割的整体,参见[item40](../7.TheConcurrencyAPI/item40.md))通常会是一个开销更小的方法。(然而它是否轻量取决于你使用的硬件和标准库中互斥量的实现。)以下是如何使用`std::atomic`来统计调用次数。
87
87
88
88
```c++
89
89
class Point { //2D点
Original file line number Diff line number Diff line change @@ -40,9 +40,9 @@ auto aw2 = std::move(aw1);
40
40
41
41
注意` aw1 ` 中的元素被** 移动** 到了` aw2 ` 中。假定` Widget ` 类的移动操作比复制操作快,移动` Widget ` 的` std::array ` 就比复制要快。所以` std::array ` 确实支持移动操作。但是使用` std::array ` 的移动操作还是复制操作都将花费线性时间的开销,因为每个容器中的元素终归需要拷贝或移动一次,这与“移动一个容器就像操作几个指针一样方便”的含义相去甚远。
42
42
43
- 另一方面,` std::string ` 提供了常数时间的移动操作和线性时间的复制操作。这听起来移动比复制快多了,但是可能不一定。许多字符串的实现采用了小字符串优化(* small string optimization* ,SSO)。“小”字符串(比如长度小于15个字符的)存储在了` std::string ` 的缓冲区中,并没有存储在堆内存,移动这种存储的字符串并不必复制操作更快 。
43
+ 另一方面,` std::string ` 提供了常数时间的移动操作和线性时间的复制操作。这听起来移动比复制快多了,但是可能不一定。许多字符串的实现采用了小字符串优化(* small string optimization* ,SSO)。“小”字符串(比如长度小于15个字符的)存储在了` std::string ` 的缓冲区中,并没有存储在堆内存,移动这种存储的字符串并不比复制操作更快 。
44
44
45
- SSO的动机是大量证据表明,短字符串是大量应用使用的习惯。使用内存缓冲区存储而不分配堆内存空间,是为了更好的效率。然而这种内存管理的效率导致移动的效率并不必复制操作高 ,即使一个半吊子程序员也能看出来对于这样的字符串,拷贝并不比移动慢。
45
+ SSO的动机是大量证据表明,短字符串是大量应用使用的习惯。使用内存缓冲区存储而不分配堆内存空间,是为了更好的效率。然而这种内存管理的效率导致移动的效率并不比复制操作高 ,即使一个半吊子程序员也能看出来对于这样的字符串,拷贝并不比移动慢。
46
46
47
47
即使对于支持快速移动操作的类型,某些看似可靠的移动操作最终也会导致复制。[ Item14] ( ../3.MovingToModernCpp/item14.md ) 解释了原因,标准库中的某些容器操作提供了强大的异常安全保证,确保依赖那些保证的C++98的代码在升级到C++11且仅当移动操作不会抛出异常,从而可能替换操作时,不会不可运行。结果就是,即使类提供了更具效率的移动操作,而且即使移动操作更合适(比如源对象是右值),编译器仍可能被迫使用复制操作,因为移动操作没有声明` noexcept ` 。
48
48
You can’t perform that action at this time.
0 commit comments