程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 明明白白c++ 解讀effective c++系列一(條目1-5)

明明白白c++ 解讀effective c++系列一(條目1-5)

編輯:C++入門知識

前言
雖然做了幾年的C/C++開發,但是總體上感覺自己的基礎方面還是有些薄弱,很多細節問題沒有了解清楚,希望寫blog來加深自己的理解。

最近看這本書,覺得受益匪淺,所以決定寫一些文章,來介紹一下自己對這些條目的理解。

 

條款一:盡量使用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.
而且即使這樣做了,出現 ++ ,--等符號還是會有問題。 大家可以看書中講述的例子。
這個就是宏定義最大的問題。
所以使用內聯函數代替的話就沒有這個麻煩了,可以寫成
[cpp] 
inline      MAX(int a, int b) 
 { 
    return   a:b?a>b 

inline      MAX(int a, int b)
 {
    return   a:b?a>b
}
但是宏定義本身的特點是適應於多種情況,這個時候我們要使用模板來解決這個問題


[cpp]
#define MAX(a,b)    ((a)>(b)? (a):(b))  
 
template  <typename  T> 
inline const T&   max(T &a, T &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;
}
這樣寫的好處,效率上和宏一樣高,而且比宏好維護,我們不用再去記憶宏定義的時候要所有的地方都加括號,也不用在調用宏函數的時候戰戰兢兢的,不用使用++ , --等符號,有的時候還要自己把它展開看一下。


下面有個完整的程序,分析這個問題
[cpp] 
#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; 
 

#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是什麼意思,但是用流來表示就不利於閱讀了,這個看應用場景。

 


[cpp] 
#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); 

#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
我們先看一個例子
[cpp] 
int main() 

   int *p; 
   int *q; 
    
   p = new int[10]; 
   q = (int*)malloc(sizeof(int)*10); 
 } 

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[]一樣,但是復雜類型就不一樣了。看下面的例子。


[cpp] 
#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; 

#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要明確的告訴是一個對象,還是對象數組。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved