《21天学通C++(第7版)》——12.4 函数运算符operator()

12.4 函数运算符operator()

21天学通C++(第7版)
operator()让对象像函数,被称为函数运算符。函数运算符用于标准模板库(STL)中,通常是STL算法中。其用途包括决策。根据使用的操作数数量,这样的函数对象通常称为单目谓词或双目谓词。下面分析一个非简单的函数对象,如程序清单12.11所示,以便理解使用如此有意思的名称的原因!

程序清单12.11 一个使用operator()实现的函数对象

输出:

分析:
第8~11行实现了operator(),然后在main()函数的第18行使用了它。注意,之所以能够在第18行将对象mDisplayFuncObject用作函数,是因为编译器隐式地将它转换为对函数operator()的调用。

因此,这个运算符也称为operator()函数,对象CDisplay也称为函数对象或functor。第21章将详尽地讨论这个主题。

C++11
用于高性能编程的移动构造函数和移动赋值运算符
移动构造函数和移动赋值运算符乃性能优化功能,属于C++11标准的一部分,旨在避免复制不必要的临时值(当前语句执行完毕后就不再存在的右值)。对于那些管理动态分配资源的类,如动态数组类或字符串类,这很有用。

1.不必要的复制带来的问题
请看程序清单12.5实现的加法运算符,注意到它创建并返回一个拷贝;减法运算符亦如此。使用下面的语法创建新的MyString实例时,情况将如何呢?

这种方式非常直观,它使用双目加法运算符(+)将三个字符串拼接起来。该运算符的实现类似于下面这样:

这个加法运算符(+)让您能够使用直观的表达式轻松地拼接字符串,但也可能导致性能问题。创建sayHello时,需要执行加法运算符两次,而每次都将创建一个按值返回的临时拷贝,导致执行复制构造函数。复制构造函数执行深复制,而生成的临时拷贝在该表达式执行完毕后就不再存在。总之,该表达式导致生成一些临时拷贝(准确地说是右值),而它们在当前语句执行完毕后就不再需要。这一直是C++带来的性能瓶颈,直到最近才得以解决。

C++11解决了这个问题:编译器意识到需要创建临时拷贝时,将转而使用移动构造函数和移动赋值运算符——如果您提供了它们。

2.声明移动构造函数和移动赋值运算符
移动构造函数的声明语法如下:

从上述代码可知,相比于常规赋值构造函数和复制赋值运算符的声明,移动构造函数和移动赋值运算符的不同之处在于,输入参数的类型为MyClass&&。另外,由于输入参数是要移动的源对象,因此不能使用const进行限定,因为它将被修改。返回类型没有变,因为它们分别是构造函数和赋值运算符的重载版本。

在需要创建临时右值时,遵循C++的编译器将使用移动构造函数(而不是复制构造函数)和移动赋值运算符(而不是复制赋值运算符)。移动构造函数和移动赋值运算符的实现中,只是将资源从源移到目的地,而没有进行复制。程序清单12.12演示了如何使用这两项C++11新增功能对MyString类进行优化。

程序清单12.12 除复制构造函数和复制赋值运算符外,还包含移动构造函数和移动赋值运算符的MyString类

输出:
没有移动构造函数和移动赋值构造函数(将第95~119行注释掉)时的输出:

添加移动构造函数和移动赋值构造函数后的输出:

分析:
这个代码示例很长,但大部分都在本书前面介绍过。在该程序清单中,最重要的部分是第95~119行,其中实现了移动构造函数和移动赋值运算符。这些C++11新增功能生成的输出使用粗体表示。注意到相比于没有这两个实体时,输出变化很大。如果您查看移动构造函数和移动赋值运算符的实现,将发现移动语义基本上是通过接管移动源中资源的所有权实现的,如移动构造函数的第101行和移动赋值运算符的第114行所示。接下来,将移动源指针设置为NULL,如第102和115行所示。这样,移动源被销毁时,通过析构函数(第16~20行)调用的delete什么也不会做,因为所有权已转交给目标对象。注意到在没有移动构造函数时,将调用复制构造函数,它对指向的字符串进行深复制。总之,移动构造函数避免了不必要的内存分配和复制步骤,从而节省了大量的处理时间。

移动构造函数和移动赋值运算符是可选的。不同于复制构造函数和复制赋值运算符,如果您没有提供移动构造函数和移动赋值运算符,编译器并不会添加默认实现。

对于管理动态分配资源的类,可使用C++11新增的这项功能对其进行优化,避免在只需临时拷贝的情况下进行深复制。

本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。

时间: 2025-01-15 15:19:02

《21天学通C++(第7版)》——12.4 函数运算符operator()的相关文章

《21天学通C++(第7版)》导读

前言 21天学通C++(第7版) 对C++来说,2011是个很特别的年份.在这一年,C++11终于获批成为新标准,它新增了一些可提高编程效率的关键字和结构,让您能够编写更优质的代码.本书旨在帮助您循序渐进地学习C++11,其中的章节经过仔细编排,从实用的角度介绍这种面向对象的编程语言的基本知识.读者只需每天花1小时,在学完本书后,就能掌握C++11. 学习C++的最佳方式是动手实践.本书包含丰富的代码示例,有助于读者提高编程技能,请务必亲自动手尝试这些代码.这些代码片段都使用了(在本书编写时)最

《21天学通C语言(第6版•修订版)》一导读

前 言 21天学通C语言(第6版•修订版) 本书旨在引导读者在21天内学通C语言编程.虽然有来自诸如C++.Java和C#的激烈竞争,但很多初学编程者还是会选择C语言.正如第1天课程介绍的原因,选择C语言可确保您不会误入"歧途". 将本书作为自学C语言的教材是一个明智的决定.虽然市面上有很多有关C语言的图书,但本书介绍C语言的方式最为合理,也让读者学习起来最为容易.本书的前五版都登上了畅销书排行榜,这一事实表明我们的观点得到了读者的认同.本书是按读者每天阅读一章的方式编写的.读者不需要

《21天学通C语言(第6版•修订版)》一1.2 为何要使用C语言

1.2 为何要使用C语言 21天学通C语言(第6版•修订版) 在当前的计算机编程领域中,有大量的高级语言可供选择,如C.Perl.BASIC.Java和C#.这些都是非常卓越的语言,适合用于完成大部分编程任务.虽然如此,但基于以下几个原因,很多计算机专业人员认为C语言是其中最佳的: C语言功能强大.灵活.使用C语言能够完成的工作只受限于您的想象力,语言本身不会给您带来任何约束.C语言可用于完成操作系统.字处理器.图形.电子表格等项目,甚至可用于编写其他语言的编译器. C语言很流行,是专业程序员的

《21天学通C语言(第7版)》一导读

前言 21天学通C语言(第7版) 从书名便可看出,通过学习本书,你可以自学C程序设计语言.在众多语言(如C++.JAVA和C#)中,C仍然是学习程序设计语言的首选.第1课中将详细介绍其中的原因.选择C作为程序设计语言是明智之举. 与市面上其他C语言的书籍相比,本书的讲解逻辑更清晰,初学者更容易理解.之前的6个版本一直在畅销书排行榜上遥遥领先,广受读者赞誉!本书为读者量身定制,每天只需花一小时便可学完一课内容.读者不需要有任何编程经验,当然,如果有其他语言的基础(如BASIC),学起来会更快.本书

《21天学通C++(第7版)》——17.2 典型的vector操作

17.2 典型的vector操作 21天学通C++(第7版) std::vector类的行为规范和公有成员是由C++标准定义的,因此,遵循该标准的所有C++编程平台都支持本章将介绍的vector操作. 17.2.1 实例化vector vector是一个模板类,需要使用第14章介绍的方法进行实例化.要实例化vector,需要指定要在该动态数组中存储的对象类型: 要声明指向list中元素的迭代器,可以这样做: 如果需要可用于修改值或调用非const函数的迭代器,可使用iterator代替const

《21天学通C++(第7版)》——17.6 问与答

17.6 问与答 21天学通C++(第7版) **问:vector会改变其存储的元素的顺序吗? 答:**vector是一种顺序容器,元素的存储顺序与插入顺序相同. **问:要将元素插入到vector中,应使用哪个函数?元素将插入到vector的什么位置? 答:**成员函数push_back将元素插入到vector末尾. **问:哪个函数用于获悉存储在vector中的元素个数? 答:**成员函数size ()返回存储在vector中的元素个数.对于所有STL容器,该函数都如此. 问:随着vecto

《21天学通Java(第6版)》—— 1.5 组织类和类行为

1.5 组织类和类行为 21天学通Java(第6版) Java面向对象编程还涉及另外三个概念:继承.接口和包,这些都是用于组织类和类行为的机制. 1.5.1 继承 继承是面向对象编程中最重要的概念之一,直接影响您如何设计和编写Java类. 继承是一种机制,让一个类能够继承另一个类的所有行为和属性. 通过继承,一个类可自动拥有现有类的所有功能,因此只需定义与现有类不同的地方. 通过继承,所有的类(无论是您创建的类,还是Java类库中的类)都以严格的层次结构来组织. 继承其他类的类叫子类,被继承的类

《21天学通C语言(第7版)》一6.2 控制程序的执行

6.2 控制程序的执行 21天学通C语言(第7版) C程序默认的执行顺序是自上而下.从main()函数的起始位置开始,逐条执行语句,直至main()函数的末尾.然而,在实际的C程序中,很少严格按这样的顺序执行.C语言提供了各种程序控制语句,方便程序员控制程序的执行顺序.第4课介绍了一种程序控制语句--if语句,接下来介绍另外3种有用的控制语句: for语句: while语句: do...while语句. 6.2.1 for语句 for语句是由一条或多条语句组成的块.for语句有时也被称为for循

《21天学通Java(第6版)》—— 2.5 表达式和运算符

2.5 表达式和运算符 21天学通Java(第6版) 表达式是一条能够提供值的语句.最常见的是数学表达式,如下面的例子所示: 这3条语句都是表达式-它们提供了可被赋给变量的值.第1条语句将字面量3赋给变量x.第2条语句将变量x的值赋给变量y.在第3条语句中,乘法运算符*用来将x和y相乘,结果存储在变量z中. 表达式可以是任何变量.字面量和运算符的组合,也可以是方法调用,因为方法能够将一个值返回给调用它的类或对象. 您知道,表达式所提供的值称为返回值.在Java程序中,可将这个值赋给变量或以其他方