2012年4月4日 星期三

[筆記] 如何宣告初始值?

 作者  ie945167 (龍蝦)                                      站內  Lobster
 標題  [筆記] 如何宣告初始值?
 時間  2012/04/04 Wed 17:09:57
───────────────────────────────────────

不負責任聲明:以下憑印象+google寫成,有錯誤很正常 0rz

              如果有人願意指出錯誤,我會很感謝您的 <(_ _)>

--------------------本文開始分隔線--------------------


一般人在宣告初始值時,大部分都採用下面的方式

T::T()
{
    a = XXX;
    b = XXX;
    c = XXX;
}

也有另一種做法如下

T::T()
: a(120), b(0.3), c(5)
{

}

這兩者有差嗎?以結果來看沒差。
但在執行效率上,後者會較快

因為前者的做法,等於後者做兩次
原因我也沒有辦法說得很清楚
大家可以去看這篇文章
http://imandrewliao.blogspot.com/2009/01/c-1.html
或是去參考 Effective C++ 這本書

重點是,後者在使用上有個限制,就是給初始值的順序要與變數宣告的順序一致
不然給值時會發生錯誤
原因同樣在上述 blog 文章中可以看到

--------------------------------------------------
以下為全文轉貼,避免連結失效

變數初值

程式寫這麼久,以前經常會遇到,"啊? C++不可以這樣嗎?"或者是"這樣寫有差別嗎?"
的驚訝

想說這可能不只是只有我有的感覺,因此把這些東西分享出來,給大家做參考

你也可以參考Effective C++這本書籍:

初值化(Initial)和給定數值(Assign)

(a) 什麼是initial?
    變數宣告的時候,直接給了數值,像是:
    int a=10;

(b) 什麼是Assign?
    變數宣告完後,再另外給定數值,像是:
    int a;
    a=10;

這兩種寫法有差異嗎? 對build-in類型,像是int, float, ...沒有差別

但是對物件而言,就決定了一點點效能上的差別了,我以一個類別A來解釋:

class A
{

}; // 什麼事都沒有的類別


使用assign你必須先宣告一個物件 A a;

此時,物件已經執行了一次建構式,把內部數值初始一次

你也許會問,類別中沒有建構式啊?何來呼叫建構式?

答案是,類別雖然沒有設計建構式

但是C++標準中有幾個函式你不需要寫,C++都會幫你生出來

而你寫了,就不會幫你產生

分別是:
預設建構式: A::A(){}
解構式: A::~A(){}
複製建構式: A::A(const A &a ){}
指定運算元: A::operator =( const A& a ){}

所以當你下A a;a=b;這樣的程式時,已經執行了一次建構式,

之後再一行assign,物件又會執行一次"指定運算元",

所以你跑了兩次物件的函式。

而Initial呢? 看起來A a=b; 這樣的程式碼,

同樣是執行一次建構式,然後再執行一次指定運算元?

答案是,編譯器直接執行複製建構式,所有數值一次搞定

比起Assign快了一倍,也許不多

但是,如果你的物件內部,變數數量超多

一個assign需要執行的指令碼很多,那也許就有點可觀了:)


說到建構式,也許有人會問,他看過以下兩種程式碼,有差別嗎?
A::A()
: a(120), c(0.3)
{
}

A::A()
{
    a=120;
    c=0.3;
}

答案依照結果論而言,沒有差別,但是同樣潛在一點點效能上的差別

首先第一種方法A()後面接著的":a(...." 那行稱為 "member initializer list"

專供給物件內成員變數的初值化,與呼叫基底類別的建構式所用

在這個時候,物件的記憶體還在配置中

C++會一邊配置記憶體,一邊把你指定的數值塞進去

所以,變數給定數值的次數只有一次


而下面那種A::A(){ ... } 的方式呢?

此時記憶體已經配置完成,變數數值已經給定過了一次,而此時又再設定一次

所以跑了兩次數值給定的程序,所以會慢一滴滴。


member initializer list這麼好用,有什麼限制嗎?

有的,指定順序要跟變數宣告的順序一致

原因說過,C++會一邊配置記憶體,一邊給定數值

如果順序不對,以下的程式就可能出錯:

class A
{
    vector buf;
    int size;
    A() : buf(size), size(20)
    ....
};


你希望配置大小為size的vector的陣列,但是在 呼叫buf(size)建構時

size記憶體還沒配置出來,根本不知道size的數值

而,size(20)初值後,buf(size)已經執行過了,所以會發生錯誤

所以正確的順序:

class A
{
    int size;
    vector buf;
    A() : size(20), buf(size)
    ....
};


--
▅◣ Origin:  謠 言 報  bbs.csie.fju.edu.tw
▋◤ Author: ie945167 從 219-85-0-189-adsl-nei3.dynamic.so-net.net.tw 發表

沒有留言:

張貼留言