2012-11-30 62 views
10
void do_something() {....} 

struct dummy 
{ 
    //even I dont call this, compiler will call it fall me, they need it 
    void call_do_something() { this->do_something_member(); } 
    void do_something() {....} 
}; 

據我瞭解,在C++中每個類或結構會蘊稱 這個指針,當你要訪問的數據成員或類的成員函數 ,就這帶來的性能損失到C++?這個指針和性能損失

我的意思是

int main() 
{ 
    do_something(); //don't need this pointer 
    dummy().call_do_something(); //assume the inline is prefect 

    return 0; 
} 

call_do_something需要這個指針調用成員函數,但 時比較像do_something的C不需要這個指針,將這個指針帶來 的性能損失C喜歡的功能?

我沒有任何意義去做任何微觀優化,因爲它會給我帶來如此多的時間,但總是沒有給我帶來好的結果,我總是遵循「測量,不要想」的規則。 我想知道這個指針會因爲好奇而帶來性能損失。

+1

您無法真正調用指向對象的指針。我認爲你要找的詞是pass,除非你測量成員和非成員函數之間完全相同的很大差異,否則不值得打擾。 – chris

+0

你是什麼意思「叫這個指針」。你的意思是把'this'作爲一個參數嗎? – Pubby

+6

直到遇到性能問題時才進行微優化。做更有意義的事,而不是更快。 –

回答

8

取決於情況,但通常情況下,如果您打開了優化,則不應該比C版貴。你真正「付出」this和其他功能的唯一時機是當你使用繼承和虛函數時。除此之外,編譯器足夠智能,不會浪費時間在this中,因爲它沒有使用它。考慮以下幾點:

#include <iostream> 

void globalDoStuff() 
{ 
    std::cout << "Hello world!\n"; 
} 

struct Dummy 
{ 
    void doStuff() { callGlobalDoStuff(); } 
    void callGlobalDoStuff() { globalDoStuff(); } 
}; 

int main() 
{ 
    globalDoStuff(); 

    Dummy d; 
    d.doStuff(); 
} 

與GCC優化級別O3編譯,我得到以下拆裝(切斷多餘的垃圾,只是顯示main()):

_main: 
0000000100000dd0 pushq %rbp 
0000000100000dd1 movq %rsp,%rbp 
0000000100000dd4 pushq %r14 
0000000100000dd6 pushq %rbx 
0000000100000dd7 movq 0x0000025a(%rip),%rbx 
0000000100000dde leaq 0x000000d1(%rip),%r14 
0000000100000de5 movq %rbx,%rdi 
0000000100000de8 movq %r14,%rsi 
0000000100000deb callq 0x100000e62 # bypasses globalDoStuff() and just prints "Hello world!\n" 
0000000100000df0 movq %rbx,%rdi 
0000000100000df3 movq %r14,%rsi 
0000000100000df6 callq 0x100000e62 # bypasses globalDoStuff() and just prints "Hello world!\n" 
0000000100000dfb xorl %eax,%eax 
0000000100000dfd popq %rbx 
0000000100000dfe popq %r14 
0000000100000e00 popq %rbp 
0000000100000e01 ret 

注意到它完全優化掉兩個DummyglobalDoStuff(),並用globalDoStuff()正文替換它。 globalDoStuff()甚至沒有被調用過,也沒有構造過Dummy。相反,編譯器/優化器會用兩個系統調用來替換該代碼,以直接打印出"Hello world!\n"。教訓是,編譯器和優化器相當聰明,一般來說你不會爲你不需要的東西付費。

另一方面,假設您有一個成員函數來操作Dummy的成員變量。你可能會認爲這與C函數相比有點懲罰,對吧?可能不會,因爲C函數需要一個指向要修改的對象的指針,當您考慮它時,它正是開頭的指針。

所以一般情況下,您不會爲C++相比於C支付this額外的費用。虛擬函數可能會有一個(小)懲罰,因爲它必須查找適當的函數來調用,但情況並非如此在這裏考慮。

如果你沒有在你的編譯器中啓用優化,那麼當然,可能會有一個懲罰,但是......爲什麼你會比較非優化的代碼呢?

+3

+1 for *可能不是,因爲C函數需要一個指向要修改的對象的指針,當你考慮它時,它正是這個指針開始的地方。 =>沒有銀彈。 –

3
#include <iostream> 
#include <stdint.h> 
#include <limits.h> 
struct Dummy { 
    uint32_t counter; 
    Dummy(): counter(0) {} 
    void do_something() { 
    counter++; 
    } 
}; 

uint32_t counter = 0; 

void do_something() { counter++; } 

int main(int argc, char **argv) { 
    Dummy dummy; 
    if (argc == 1) { 
    for (int i = 0; i < INT_MAX - 1; i++) { 
     for (int j = 0; j < 1; j++) { 
     do_something(); 
     } 
    } 
    } else { 
    for (int i = 0; i < INT_MAX - 1; i++) { 
     for (int j = 0; j < 1; j++) { 
     dummy.do_something(); 
     } 
    } 
    counter = dummy.counter; 
    } 
    std::cout << counter << std::endl; 
    return 0; 
} 

上gcc版本4.3.5 10次(Debian的4.3.5-4),64位,平均無任何標誌:

與全球反:0m15.062s

與虛擬對象:0m21。259S

如果我修改這樣的代碼爲​​建議:

#include <iostream> 
#include <stdint.h> 
#include <limits.h> 

uint32_t counter = 0; 

struct Dummy { 
    void do_something() { 
    counter++; 
    } 
}; 


void do_something() { counter++; } 

int main(int argc, char **argv) { 
    Dummy dummy; 
    if (argc == 1) { 
    for (int i = 0; i < INT_MAX; i++) { 
     do_something(); 
    } 
    } else { 
    for (int i = 0; i < INT_MAX; i++) { 
     dummy.do_something(); 
    } 
    } 
    std::cout << counter << std::endl; 
    return 0; 
} 

然後,奇怪的是,

與全球反:0m12.062s

與虛擬對象:0m11.860s

+0

+1 Ooh ...一個很好的例子,證明並非所有事情都會自動過早優化。 – Mysticial

+0

是否帶有優化標誌? – Cornstalks

+0

沒有任何標記 – perreal