明明白白c++ 解读effective c++系列一(条目1-5)

前言

虽然做了几年的C/C++开发,但是总体上感觉自己的基础方面还是有些薄弱,很多细节问题没有了解清楚,希望写blog来加深自己的理解。

最近看这本书,觉得受益匪浅,所以决定写一些文章,来介绍一下自己对这些条目的理解。

给一个effective c++的下载地址http://download.csdn.net/detail/mlkiller/5335383

条款一:尽量使用const和inline,而不要使用define

宏常量

宏常量有两个问题 ,一个是没有类型,另一个是编译报错的时候比较难找,因为它以及把宏换成常量了。
所以使用const常量,可以避免上面的问题,如果是c语言写的,你还是乖乖的用宏定义吧。

宏函数

因为以前本人主要做c语言开发,自然面试的时候都会问一下关于宏定义的试题。
一道考烂的题就是,用宏定义找出两个数中最大的。
答案是
#define   MAX(a,b)    ((a)>(b)?(a):(b))
就是说所有变量,表达式以及 宏函数自身都要加括号,为什么呢?
简单说明一下
如果写成
#define   MAX(a,b)    a>b?a:b
那么我现在计算         MAX(2,3)*MAX(1,2) 就会被翻译成
         2>3?2:3*1>2?1:2
这个时候你就要查优先级表,?:的优先级小于*号,所以上面的实际结果是
2>3?2:(3>2?1:2)  
2>3?2:1
最后的结果是1
而不是我们想要的6.
而且即使这样做了,出现 ++ ,--等符号还是会有问题。 大家可以看书中讲述的例子。
这个就是宏定义最大的问题。
所以使用内联函数代替的话就没有这个麻烦了,可以写成
inline      MAX(int a, int b)
 {
    return   a:b?a>b
}

但是宏定义本身的特点是适应于多种情况,这个时候我们要使用模板来解决这个问题

#define MAX(a,b)    ((a)>(b)? (a):(b))

template  <typename  T>
inline const T&   max(T &a, T &b)
{
    return  a > b ? a :b;
}

这样写的好处,效率上和宏一样高,而且比宏好维护,我们不用再去记忆宏定义的时候要所有的地方都加括号,也不用在调用宏函数的时候战战兢兢的,不用使用++ , --等符号,有的时候还要自己把它展开看一下。

下面有个完整的程序,分析这个问题
#include <iostream>
using namespace std;

#define MAX(a,b)    ((a)>(b)? (a):(b))

template  <typename  T>
inline const T&   max(T &a, T &b)
{
    return  a > b ? a :b;
}

int main()
{
    int  a  = 4;
	int  b  = 7;
    
	cout<<MAX(++a,++b)<<endl;
	
	a = 4;
	b = 7;
	cout<<max(++a, ++b)<<endl;

}

你可以看到,输出的结果分别是9和8。


条款2:尽量用<iostream>而不用<stdio.h>

这个条款的说法,每个人有不同的看法。
 书中的说法是,你可以不用记忆那些类型,%d表示十进制书中,%s, %c,%f等等输出类型,
你也不用纠结scanf里面要取地址。
对于类的输出,你可以重写<<或者>>来定义他们的输入和输出,但是用scanf和printf来打印可能很麻烦了。

但是也有人反对用<<和>>来进行输入和输出,他们的原因很简单代码的易读性。
你读scanf和 printf里面可以看到他们会格式化输出和输出的东西,
例如你要求输入格式是 input1,input2中间必须用逗号间隔,那么iostream可能写起来就比较麻烦了。
另外printf 你可以很明显的读出来这句log是什么意思,但是用流来表示就不利于阅读了,这个看应用场景。


#include <iostream>
#include <stdio.h>
using namespace std;


int main()
{
    int a,b;
	float c,d;
	cin>>a>>c;
	cout<<a<<" "<<c<<endl;
	printf("请按1,2这种格式输入\n");
	scanf("%d ,%f", &b, &d);
	printf("%d, %f", b, d);
}


条款3:尽量用new和delete而不用malloc和free

我们先看一个例子
int main()
{
   int *p;
   int *q;
   
   p = new int[10];
   q = (int*)malloc(sizeof(int)*10);
 }

编译一下,你会发现编译不通过,为什么呢?因为new是操作符,就是类似于=, +,* 之类的符号,编译器认识他们。
但是malloc其实是个函数,编译器不认识他们,所以你要包含头文件stdlib.h。

还有什么区别呢?就是new 和delete的出现是为了类,他们会调用类的构造函数和析构函数。 但是malloc和free申请的时候并不会调用构造和析构函数,所以new和delete在c++中最好代替malloc和free.

另外一个注意的是,不要混用这四个。一定要对应。
为了简单,用new和delete 可以实现所有的功能,所以c++中推荐用这个,如果是c语言,就乖乖的用malloc 和free吧。

条款4:尽量使用c++风格的注释

c++的注释是// 而c的注释是/*  */
这里我个人觉得函数头的注释最好还是用/* */的段注释。
如果是单行的注释可以考虑用//

条款5:对应的new和delete要采用相同的形式


还有个问题,就是还有new [] 和delete[]他们是对应的,用new[]申请的要用delete[]释放。
如果用new申请,而用delete[]释放,就会导致释放的多了,会引起不可以预知的问题。
同样如果new[]申请,而用delete释放,如果是基本类型,没有问题delete和delete[]一样,但是复杂类型就不一样了。看下面的例子。

#include <stdlib.h>
#include <iostream>
using namespace std;

class A
{
public:
   int a;
};

void testInt();
void testClass();

int main()
{
   testInt();
   testClass();
 }
 
 void testInt()
 {
   int *p;
   int *q; 
   
   p = new int[10];
   q = (int*)malloc(sizeof(int)*10);  
   
   p[1] = 10;
   q[1] = 10;   
   
   delete []p;
   free(q);
   
   cout<<p[1]<<endl;
   cout<<q[1]<<endl;
}

void testClass()
{
    A *p = new A[10];
    p[1].a = 10;
	
	delete p;
	cout<<p[1].a<<endl;
}

输出的结果是
1629738516
0
10
可以看到类里面没有释放完。
因为malloc和free都是指定大小的,你分配的时候的大小是知道的,free只用把对应的空间释放掉就可以了。
而new的时候,要分两种情况,new 一个对象,还是new[]分配对象数组。
所以 delete要明确的告诉是一个对象,还是对象数组。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值