2012-11-30 8 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() {....} 
}; 

Secondo quello che so, ogni classe o struct in C++ saranno implicitamente chiamare questo puntatore quando si desidera accedere al membro di dati o la funzione di membro della classe, sarebbe questo porterà penalizzazione delle prestazioni in C++?Questo puntatore e le prestazioni di rigore

Quello che voglio dire è

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

    return 0; 
} 

call_do_something bisogno di un tale puntatore per chiamare la funzione membro, ma la C come fa_qualcosa non hanno bisogno di questo puntatore, sarebbe questo puntatore portare qualche penalizzazione delle prestazioni quando si confronta con la funzione mi piace?

non ho alcun senso di fare qualsiasi micro ottimizzazione poiché mi avrebbe causato così tanto tempo, ma sempre non mi portano buon risultato, ho sempre seguire la regola di "misura, non pensare". Voglio sapere che questo puntatore comporterebbe una penalizzazione delle prestazioni o meno a causa della curiosità.

+1

Non si può realmente chiamare un puntatore a un oggetto. Penso che la parola che stai cercando sia passata e, a meno che tu non misuri una grande differenza tra le funzioni membro e non membro che sono esattamente le stesse, non vale la pena preoccuparti. – chris

+0

Cosa intendi con "chiama questo puntatore". Intendi passare "questo" come argomento? – Pubby

+6

Non eseguire l'ottimizzazione micro finché non si riscontrano problemi di prestazioni. Fai ciò che ha più senso, non ciò che è più veloce. –

risposta

8

Dipende dalla situazione, ma in genere, se le ottimizzazioni sono attivate, non dovrebbe essere più costoso della versione C. L'unica volta in cui "paghi" veramente per this e altre funzionalità è quando usi l'ereditarietà e le funzioni virtuali. Oltre a questo, il compilatore è abbastanza intelligente da non perdere tempo su this in una funzione che non stai utilizzando. Si consideri il seguente:

#include <iostream> 

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

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

int main() 
{ 
    globalDoStuff(); 

    Dummy d; 
    d.doStuff(); 
} 

compilato con livello di ottimizzazione GCC O3, ottengo il seguente smontaggio (il taglio della spazzatura in più e solo mostrando 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 

Avviso completamente ottimizzato via sia la Dummy e globalDoStuff() e appena sostituito con il corpo di globalDoStuff(). globalDoStuff() non viene mai nemmeno chiamato, e non viene mai costruito Dummy. Invece, il compilatore/ottimizzatore sostituisce quel codice con due chiamate di sistema per stampare direttamente "Hello world!\n". La lezione è che il compilatore e l'ottimizzatore sono abbastanza intelligenti, e in generale non pagherai per quello che non ti serve.

D'altra parte, si immagini di avere una funzione membro che manipola una variabile membro di Dummy. Potresti pensare che questo abbia una penalità rispetto a una funzione C, giusto? Probabilmente no, perché la funzione C ha bisogno di un puntatore a un oggetto da modificare, che, quando ci si pensa, è esattamente ciò che il puntatore this deve iniziare.

Quindi in generale non si paga un extra per this in C++ rispetto a C. Le funzioni virtuali possono avere una (piccola) penalità in quanto deve cercare la funzione corretta da chiamare, ma non è così che siamo considerando qui.

Se non si attivano le ottimizzazioni nel compilatore, allora sì, certo, potrebbe esserci una penalità, ma ... perché dovresti confrontare il codice non ottimizzato?

+3

+1 per * Probabilmente no, perché la funzione C ha bisogno di un puntatore a un oggetto da modificare, che, quando ci si pensa, è esattamente ciò che il puntatore deve iniziare. * => non c'è un proiettile d'argento. –

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; 
} 

media di 10 prove su gcc version 4.3.5 (Debian 4.3.5-4), a 64 bit, senza bandiere:

con contatore globale: 0m15.062s

con oggetto fittizio : 0m21.259s

Se modifico il codice come questo come Lyth suggerito:

#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; 
} 

Poi, stranamente,

con contatore globale: 0m12.062s

con oggetto fittizio: 0m11.860s

+0

+1 Ooh ... Un bell'esempio che dimostra che non tutto è automaticamente ottimizzazione prematura. – Mysticial

+0

Con o senza flag di ottimizzazione? – Cornstalks

+0

senza bandiere – perreal

Problemi correlati