More Effective C++ (运算符)

4.1:谨慎定义类型转换函数

<1>容易的方法是利用一个最新的编译器特性:explicit关键字

<2>C++编译器把">>"作为一个符号来解释,在两个">"间没有空格,语句会产生语法错误。

<3>隐式类型转换函数

示例代码如下:

 1 #include<iostream>
 2 using namespace std;
 3 
 4 template<class T>
 5 class Array
 6 {
 7 public:
 8     class ArraySize
 9     {
10         public:
11             ArraySize(int numElements):theSize(numElements)
12             {
13                 cout<<"flag ArraySize(int  numElements)"<<endl;
14             }
15             int size() const
16             {
17                 cout<<"flag  size()"<<endl; 
18                 return theSize;
19             }
20         private:
21             int theSize;
22     };
23 
24     Array(int lowBound,int highBound)
25         {};
26 
27     Array(ArraySize arsize)
28     {
29         cout<<"flag Array"<<endl;
30     };
31 };
32 void main()
33 {
34     Array<int>  a(10);
35 }
36 
37 /*
38 flag ArraySize(int  numElements)
39 flag Array
40  */

4.2:自增,自减操作符前缀形式和后缀形式

<1>重载函数间的区别决定于它们的参数类型上的差异,但是不论increament或者decrement的前缀还是后缀都只有一个参数。

为了解决这个语言问题,C++规定后缀形式有一个int类型参数,当函数被调用时,编译器传递一个0作为int参数的值给该函数。

<2>前缀自增:增加然后取回;后缀自增:取回然后增加

<3>前缀形式

示例代码如下:

 1 UPInt & UPInt::operator++()
 2 {
 3     *this += 1;   //增加
 4     return *this; //取回值
 5 }
 6 const UPInt UPInt::operator++(int)
 7 {
 8     UPInt oldValue = *this;   //保留原值
 9     ++(*this);          //增加
10     return oldValue;    //返回原值
11 }

<4>后缀操作符函数没有使用它的参数。这个参数仅仅只是为了区别前缀函数调用。

<5>如果在函数内部没有使用参数,许多编译器会显示警告信息。为了避免这些信息,最常用的方式就是省略掉参数名称

<6>很明显后缀函数必须返回一个对象,但是为什么是const对象呢?假设不是const:

假设不是 const 对象,下面的代码就是正确的:

这组代码与下面的代码相同: 

i.operator++(0).operator++(0);  

很明显, 第一个调用的operator++函数返回的对象调用了第二个operator++函数。 有两个理由导致我们应该厌恶上述这种做法:

第一,是与内置类型行为不一致。当设计一个类遇到问题时,一个好的准则是使该类的行为与int 类型一致。而int 类型不允许连续进行两次后缀 increment: 

int i; 

i++++; // 错误! 

第二个原因,是使用两次后缀 increment 所产生的结果与调用者期望的不一致。

如上所示,第二次调用operator++改变的值是第一次调用返回对象的值,而不是原始对象的值。因此如果:

i++++; 是合法的,i 将仅仅增加了一次。这与人的直觉相违背,使人迷惑(对于int类型和 UPInt 都是一样),所以最好禁止这么做。

C++禁止int 类型这么做,同时你也必须禁止你自己写的类有这样的行为。

最容易的方法是让后缀 increment 返回 const 对象。当编译器遇到这样的代码:  

i++++; // same as  

i.operator++(0).operator++(0);

它发现从第一个 operator++函数返回的 const 对象又调用 operator++函数,然而这个函数是一个 non-const 成员函数, 所以 const 对象不能调用这个函数。

如果你原来想过让一个函数返回 const 对象没有任何意义,现在你就知道有时还是有用的,后缀 increment和 decrement 就是例子。 (更多的例子参见 Effective C++ 条款 21) 


如果你很关心效率问题, 当你第一次看到后缀 increment函数时,你可能觉得有些问题。

这个函数必须建立一个临时对象以做为它的返回值, (参见条款M19) ,上述实现代码建立了一个显式的临时对象(oldValue) ,这个临时对象必须被构造并在最后被析构。前缀 increment 函数没有这样的临时对象。

由此得出一个令人惊讶的结论,如果仅为了提高代码效率,UPInt 的调用者应该尽量使用前缀 increment,少用后缀 increment,除非确实需要使用后缀 increment。

让我们明确一下,当处理用户定义的类型时,尽可能地使用前缀 increment,因为它的效率较高。


我们再观察一下后缀与前缀 increment 操作符。它们除了返回值不同外,所完成的功能是一样的,即值加一。

简而言之,它们被认为功能一样。那么你如何确保后缀increment和前缀increment的行为一致呢?

当不同的程序员去维护和升级代码时,有什么能保证它们不会产生差异?除非你遵守上述代码里的原则,这才能得到确保。

这个原则是后缀 increment和 decrement 应该根据它们的前缀形式来实现。你仅仅需要维护前缀版本,因为后缀形式自动与前缀形式的行为一致。


正如你所看到的,掌握前缀和后缀 increment和decrement 是容易的。

一旦了解了他们正确的返回值类型以及后缀操作符应该以前缀操作符为基础来实现的规则,就足够了。

4.3:不要重载“&&”,“||”,或“,”

<1>char *p; if((p!=0)&&(strlen(p)>10))......

注意这个if条件的写法顺序

<2>运算符重载要求:

4.4:理解各种不同含义的new和delete

<1>new operator 称为new操作符与operator new称为new操作

string *ps = new string("Memory Management");

使用的是new operator ,即就是new操作符,这种用法是不可改变的,功能总是相同的。

完成两部分任务:第一,分配足够的内存以便容纳所需类型的对象;第二,它调用构造函数初始化内存中的对象。

而我们所能改变的是如何为对象分配内存。

new操作符调用一个函数来完成必需的内存分配,你能够重写或重载这个函数来改变它的行为。

new操作符为分配内存所调用函数的名字是 operator new。

原型如下:

void * operator new(size_t size);

调用形式与其他函数一样:

void *rawMemory=operator new(sizeof(string));

placement new旨在完成一种情况,那就是假如我们已经申请到了内存,想要在该内存上构建对象,就选择placement new

三种情况代码如下:

 1 #include<iostream>
 2 using namespace std;
 3 
 4 class  Test
 5 {
 6     int a;
 7 public:
 8     Test(int data = 10):a(data)
 9     {
10         cout<<"Construction :"<<this<<endl;
11     }
12     ~Test()
13     {
14         cout<<"Destroy :"<<this<<endl;
15     };
16 };
17 void  main()
18 {
19     //new操作符(new operator)
20     Test *pa = new Test[2];  //完成两部分任务
21     delete []pa;
22     pa = NULL;
23     
24     //new函数(operator  new)  
25     void  *pb = operator  new(sizeof(Test));  //仅仅只是分配一块内存,类似于malloc
26     operator  delete(pb);
27     pb = NULL;
28     
29     //placement new 
30     void  *suffer = malloc(sizeof(Test));  
31     Test *pc = new(suffer)  Test(100);  //在已经申请的内存上建立自己的对象
32     pc->~Test();
33     free(suffer);
34     suffer = NULL;
35 }

总结:

如果想在堆上创建一个对象,应该用new操作符,它分配内存,同时又为对象调用构造函数。

如果仅仅想分配内存,就用operator new函数,它不会调用构造函数

如果你想定制自己的在堆对象被建立时的内存分配过程,应该重载写你自己的operator new函数,new操作符会调用你定制的operator new

如果想在一块已经分配好的内存里建立一个对象,使用placement new

<2>delete操作符与operator delete的关系与new操作符与operator new的关系一样

delete p;

导致编译器生成类似的代码:

p->~Class();

operator delete(p);

 

转载于:https://www.cnblogs.com/Braveliu/archive/2013/01/06/2847167.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/379021.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php微信获取mediaid超出限制_Python实现每日微信自动打卡

众所周知&#xff0c;因为疫情的原因&#xff0c;很多高校和公司都要求员工每日在微信上进行打卡&#xff0c;来汇报自己的当前身体状态和所处地区。但绝大多数情况下&#xff0c;每天打卡的信息其实是不会变的&#xff0c;我们要做的就是进入公众号——自动登录点进打卡页面—…

ffplay 分析(音频从Frame(解码后)队列取数据到SDL输出)

《ffplay的数据结构分析》 《ffplay分析&#xff08;从启动到读取线程的操作&#xff09;》 《ffplay分析&#xff08;视频解码线程的操作&#xff09;》 《ffplay分析&#xff08;音频解码线程的操作&#xff09;》 《ffplay分析 &#xff08;视频从Frame(解码后)队列取数据到…

pandas 根据列名索引多列数据_Pandas 数据聚合与分组运算[groupby+apply]速查笔记

利用Pandas将数据进行分组&#xff0c;并将各组进行聚合或自定义函数处理。Pandas中Groupby分组与聚合过程导入模块import pandas as pd缩写df表示Dataframe对象分组df.groupby(col1)&#xff1a; 根据col1列将df全部列分组&#xff08;默认&#xff1a;axis0行&#xff09;df[…

ffplay分析 (视频从Frame(解码后)队列取数据到SDL输出)

《ffplay的数据结构分析》 《ffplay分析&#xff08;从启动到读取线程的操作&#xff09;》 《ffplay分析&#xff08;视频解码线程的操作&#xff09;》 《ffplay分析&#xff08;音频解码线程的操作&#xff09;》 《ffplay 分析&#xff08;音频从Frame(解码后)队列取数据到…

redis 备份导出rdb_Redis数据迁移利器之redisshake

“当需要进行Redis实例或集群数据迁移时&#xff0c;我们可以采用导出/导入的方式进行数据迁移&#xff0c;但当需要做数据异地灾备或双活时&#xff0c;再使用传统的方式就不合适了&#xff0c;我们需要借助工具(如redis-port/redis-shake)来完成。”redis-shake介绍redis-sha…

线性结构常规操作(四)

定义存储结构(以单向链表为主) 对于链表的定义&#xff0c;通过结构体进行定义&#xff0c;包括两部分&#xff0c;一是数据域&#xff0c;另一个就是指针&#xff0c;用于指向下一个节点。 1&#xff0c;创建链表 定义链表&#xff1a; struct nodesq{int data;//数据域&a…

ffplay分析 (暂停 / 播放处理)

《ffplay的数据结构分析》 《ffplay分析&#xff08;从启动到读取线程的操作&#xff09;》 《ffplay分析&#xff08;视频解码线程的操作&#xff09;》 《ffplay分析&#xff08;音频解码线程的操作&#xff09;》 《ffplay 分析&#xff08;音频从Frame(解码后)队列取数据到…

源码 状态机_[源码阅读] 阿里SOFA服务注册中心MetaServer(1)

[源码阅读] 阿里SOFA服务注册中心MetaServer(1)0x00 摘要0x01 服务注册中心1.1 服务注册中心简介1.2 SOFARegistry 总体架构1.3 为什么要分层0x02 MetaServer2.1简介2.2 问题0x03 代码结构0x04 启动运行4.1 集成部署4.2 独立部署0x05 总体逻辑5.1 程序主体5.2 配置0x06 启动6.1…

HttpService远程校验

今天学了下HttpService&#xff0c;和大家分享一下。HttpService是用来读取远程数据的一个对象&#xff0c;数据格式为XML。 我做了一个登陆校验的功能&#xff0c;主要是通过HttpService将服务器端的用户数据得到&#xff0c;然后在客户端判断输入的用户名和密码是否存在。 主…

免费开源FTP Server软件FileZilla Server

很多朋友在实际应用中都可能需要用到FTP Server类的软件&#xff0c;这类软件有很多&#xff0c;比较知名的有Serv&#xff0d;U、G6等&#xff0c;这里向大家介绍一下FileZilla Server&#xff0c;Windows平台下一款不错的FTP Server软件&#xff0c;而且是免费的、开源的。 S…

ffplay分析 (seek操作处理)

《ffplay的数据结构分析》 《ffplay分析&#xff08;从启动到读取线程的操作&#xff09;》 《ffplay分析&#xff08;视频解码线程的操作&#xff09;》 《ffplay分析&#xff08;音频解码线程的操作&#xff09;》 《ffplay 分析&#xff08;音频从Frame(解码后)队列取数据到…

android 代码设置 键盘适应_硬核软件,能在电脑上控制iPhone和Android手机

在电脑上控制手机大概已经不是什么新鲜操作&#xff0c;小米、华为都为自家手机和电脑的联动推出了同屏操作之类的功能&#xff0c;此外也可以通过开源软件Scrcpy来在Windows或者macOS上实现对安卓手机的控制&#xff0c;这些基本都只针对安卓手机。近期&#xff0c;奇客君发现…

ijkplayer 消息循环处理过程分析

ijkplayer 消息循环处理过程分析简介一、消息队列初始化1、 initWithContentURLString函数2、 ijkmp_ios_create函数3、 ijkmp_create函数二、消息队列的消息循环处理函数启动1、prepareToPlay函数2、ijkmp_prepare_async函数3、ijkmp_prepare_async_l函数4、ijkmp_msg_loop函数…

json解析对应的value为null_徒手撸一个JSON解析器

Java大联盟致力于最高效的Java学习关注作者 | 田小波cnblogs.com/nullllun/p/8358146.html1、背景JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。相对于另一种数据交换格式 XML&#xff0c;JSON 有着诸多优点。比如易读性更好&#xff0c;占用空间更少等。在 …

平院Python习题

在读写文件之前&#xff0c;用于创建文件对象的函数是&#xff08; A &#xff09;。 A&#xff0e; open B&#xff0e; create C&#xff0e; file D&#xff0e;folder 解析&#xff1a; open(file, mode‘r’, buffering-1, encodingNone, errorsNone, newlineNone, close…

搭建srs服务器(rtmp)

搭建srs服务器&#xff08;rtmp&#xff09; 目录:1、下载srs源码&#xff08;从码云上&#xff09;&#xff1a;2、 切换到srs.oschina&#xff1a;3、 这里使用3.0版本&#xff1a;4、 切换到trunk&#xff1a;5、 编译&#xff1a;6、 启动&#xff1a;7、查看日志输出&…

2560介绍_炒股高手收益翻10倍,只因妙用这一招2560战法,看了都不亏了

(本文由公众号越声研究(yslc927yj)整理&#xff0c;仅供参考&#xff0c;不构成操作建议。如自行操作&#xff0c;注意仓位控制和风险自负。)选股是每个刚入市的新股民需掌握的技巧&#xff0c;通过资金选股了解资金流向&#xff0c;善用工具轻松选股&#xff0c;同时多留意行业…

rtmp协议分析(三次握手)

RTMP详细分析(Message 消息&#xff0c;Chunk分块) librtmp分析&#xff08;发送数据包处理&#xff09; librtmp分析&#xff08;接收数据包处理&#xff09; RTMP协议是Real Time Message Protocol(实时信息传输协议)的缩写&#xff0c;它是由Adobe公司提出的一种应 用层的协…

合并文件夹中子目录_01 Linux之统计文件夹中文件个数以及目录个数

案例分析&#xff1a;今天遇到了一个需要统计路径下目录个数的问题如果一个一个的去数会很麻烦&#xff0c;找到了一篇文章刚好提到这个&#xff0c;于是我将方法整理了一下。该方法的链接&#xff1a;Linux统计文件夹中文件个数以及目录个数_SG匚hang的博客-CSDN博客_linux统计…

关于Makefile,Makefile.in,Makefile.am,Configure功能及相互关系的问题

目录makefile写法1. 简介2. 上路之前3. 一个简单的例子4.说明&#xff1a;4.1、autoscan4.2、 configure.scan4.3、aclocal4.4、autoconf4.5、Makefile.am4.6、 automake4.7、Makefilemakefile写法 在 Unix 上写程式的人大概都碰过 Makefile&#xff0c;尤其是用 C 来开发程式…