2009-10-04 24 views
6

當我讀litb answer to this question時,我瞭解到通過引用傳遞數組可以讓我們獲得它的大小。我只是打點點的代碼,並試圖通過引用傳遞一個「功能」和令人驚訝的(至少對我來說),這個代碼編譯:在這種情況下,有人可以解釋「參考」和「指針」之間的區別嗎?

void execute(void (&func)()) // func is passed by reference! 
{ 
    func(); 
} 

是否有最後一個函數之間的差異,而這一次:

void execute(void (*func)()) // func is passed by pointer! 
{ 
    func(); 
} 

我試過使用VC2008,它在每種情況下產生不同的輸出。奇怪的是,編譯器優化的代碼更好的函數指針的情況:

void print() 
{ 
    std::cout << "Hello References!"; 
} 
void execute(void (&func)()) // optimized 
{ 
    func(); 
} 
int main() 
{ 
    00291020 call print (291000h) 
} 
========================================= 
// In this case, the compiler removes all function calls in the code! 
void print() // optimized! 
{ 
    std::cout << "Hello Pointers!"; 
} 
void execute(void (*func)()) // optimized 
{ 
    func(); 
} 
int main() 
{ 
    002F1005 push offset string "Hello References!" (2F2124h) 
    002F100A push eax 
    002F100B call std::operator<<<std::char_traits<char> > (2F1150h) 
} 

必須有一個區別,雖然我看不出來,是吧?

注意:代碼是使用VC2008編譯的,其中/O2/Ot已打開。


編輯::我對函數引用和函數指針之間的任何差異很感興趣。我檢查了生成的彙編代碼,以瞭解每種情況下的翻譯過程。

+0

是您在優化行爲或只是有興趣一般功能參考信息? – 2009-10-04 19:37:24

+0

@litb我真的很驚訝我可以通過引用傳遞一個函數。如果你有關於函數指針的功能差別或其他方面的解釋,那將是非常好的:) – AraK 2009-10-04 19:51:46

回答

3

對於語言的差異(只保留下函數聲明,因爲這就是很重要的只有)

void execute(void (&func)()); 

void g(); 
int main() { 
    void (*fp)() = g; 
    execute(fp); // doesn't work 
    execute(&g); // doesn't work either 
    execute(g); // works 
} 

它不工作,因爲它要的功能,而不是一個函數指針。出於與數組答案拒絕指針相同的原因,這也會拒絕指針。你必須直接傳遞「g」。

對於模板,這也很重要

template<typename T> 
void execute(T &t) { T u = t; u(); } 

template<typename T> 
void execute(T t) { T u = t; u(); } 

這兩個彼此非常不同。如果你用上面的execute(g);來調用它,那麼第一個將嘗試聲明一個函數,並用t(參考g)初始化它。生成的功能應該是這樣的

void execute(void(&t)()) { void u() = t; u(); } 

現在可以初始化引用和函數指針,但當然不是函數本身。在第二個定義中,T將通過模板參數推導推斷爲函數指針類型,並且傳遞一個函數會將其隱式轉換爲該指針參數類型。所以一切都會好起來的。


我不知道爲什麼MSVC爲了內聯處理它們不同 - 但我也懷疑這是因爲函數引用更少出現。

+0

'execute(* fp);' - 但是 - 缺少的第四種情況:-) – 2011-10-27 23:49:11

3

這不是一個普通的習語,所以它可能就是VS團隊沒有添加規則來優化它。

3

我認爲這是由於C++標準4.3:

功能類型T的左值可以轉換爲類型的「指針T.」右值的結果是一個指針,指向 功能。

+0

有趣的報價。這並不意味着在轉換函數引用後,在兩種情況下都應該生成基本相同的代碼。我知道這是一個實現細節,但編譯器如何優化指針而不是引用(如果已轉換)? – AraK 2009-10-04 18:31:32

-2

參考文獻(&)與指針(*)之間的區別在於參考文獻提供了變量或位置的地址,並且指針指向存儲在其中的地址在存儲器中的位置。

int *pointer; 
int variable; 

pointer = &variable; // assigning the address of variable to pointer 

variable = 53; // value of variable 

cout << *pointer; // This should output the value of the address where is pointing, in this 
        // case 53, that is the value of variable to where is pointing. 

我們可以得出這樣的結論(&變量)具有記憶位置,並anyname點存儲在內存中的地址的地址* ...

+0

_「該引用提供變量的地址或位置,並且指針指向存儲器中存儲的地址的位置在其中。「_嗯......我認爲你是混淆的地址的運營商的參考。 – 2015-04-20 19:12:56

相關問題