Strafe

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() {....} 
}; 

Nach was ich weiß, wird jede Klasse oder Struktur in C++ implicity nennen diesen Zeiger, wenn Sie das Datenelement oder Elementfunktion der Klasse zugreifen wollen, würde dies Leistungseinbußen bringen nach C++?Strafe

Was ich meine, ist

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

    return 0; 
} 

call_do_something brauchen einen diesen Zeiger die Memberfunktion zu rufen, sondern die C wie do_something brauchen nicht diesen Zeiger, würde dieser Zeiger eine Leistungseinbuße bringen, wenn Vergleich zu die C-ähnliche Funktion?

Ich habe keine Bedeutung, irgendeine Mikrooptimierung zu tun, da es mir so viel Zeit bringen würde, aber bringen Sie mir immer kein gutes Ergebnis, ich folge immer der Regel "Maß, denke nicht". Ich möchte wissen, dass dieser Zeiger wegen der Neugier Leistung bringen würde oder nicht.

+1

Sie können einen Zeiger auf ein Objekt nicht wirklich aufrufen. Ich denke, das Wort, nach dem Sie suchen, ist bestanden, und wenn Sie nicht einen großen Unterschied zwischen Member- und Nicht-Member-Funktionen messen, die genau gleich sind, lohnt es sich nicht, sich damit zu beschäftigen. – chris

+0

Was meinen Sie "diesen Zeiger nennen". Meinst du das "als Argument"? – Pubby

+6

Führen Sie keine Mikrooptimierung durch, bis Sie Leistungsprobleme haben. Tun Sie, was mehr Sinn macht, nicht was schneller ist. –

Antwort

8

Abhängig von der Situation, aber normalerweise, wenn Sie Optimierungen aktiviert haben, sollte es nicht teurer als die C-Version sein. Die einzige Zeit, in der Sie wirklich für this und andere Funktionen bezahlen, ist, wenn Sie Vererbung und virtuelle Funktionen verwenden. Ansonsten ist der Compiler intelligent genug, um keine Zeit auf this in einer Funktion zu verschwenden, die Sie nicht verwenden. Beachten Sie Folgendes:

#include <iostream> 

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

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

int main() 
{ 
    globalDoStuff(); 

    Dummy d; 
    d.doStuff(); 
} 

Zusammengestellt mit GCC Optimierungsstufe O3, erhalte ich die folgende Zerlegung (die extra Junk schneiden und nur zeigen 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 

Hinweis es vollständig wegoptimiert sowohl die Dummy und globalDoStuff() und ersetzte es nur durch den Körper von globalDoStuff(). globalDoStuff() wird nie überhaupt genannt, und kein Dummy wird jemals gebaut. Stattdessen ersetzt der Compiler/Optimierer diesen Code durch zwei Systemaufrufe, um "Hello world!\n" direkt auszudrucken. Die Lektion ist, dass der Compiler und der Optimierer ziemlich schlau sind, und im Allgemeinen bezahlen Sie nicht für das, was Sie nicht brauchen.

Auf der anderen Seite, stellen Sie sich vor, Sie haben eine Member-Funktion, die eine Elementvariable von Dummy manipuliert. Sie könnten denken, dass dies eine Strafe im Vergleich zu einer C-Funktion hat, oder? Wahrscheinlich nicht, weil die C-Funktion einen Zeiger auf ein zu modifizierendes Objekt benötigt, was, wenn Sie darüber nachdenken, genau das ist, was der Zeiger mit this anfangen soll.

Also im Allgemeinen werden Sie nicht extra für this in C++ im Vergleich zu C bezahlen. Virtuelle Funktionen können eine (kleine) Strafe haben, da es die richtige Funktion nachschlagen muss, aber das ist nicht der Fall, den wir sind hier betrachtend.

Wenn Sie in Ihrem Compiler keine Optimierungen einschalten, dann ist es sicher, dass es eine Strafe gibt, aber ... warum würden Sie nicht optimierten Code vergleichen?

+3

+1 für * Wahrscheinlich nicht, weil die C-Funktion einen Zeiger auf ein Objekt benötigt, um zu ändern, was, wenn Sie darüber nachdenken, genau das ist, was der Zeiger mit beginnen soll. * => Es gibt keine Silberkugel. –

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

Durchschnitt von 10 Läufen auf gcc Version 4.3.5 (Debian 4.3.5-4) 64bit, ohne Fahnen:

mit globalen Zählern: 0m15.062s

mit Dummy-Objekt : 0m21.259S

Wenn ich den Code wie folgt als Lyth ändern vorgeschlagen:

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

Dann seltsam,

mit globalen Zähler: 0m12.062s

mit Dummy-Objekt: 0m11.860s

+0

+1 Ooh ... Ein schönes Beispiel, das beweist, dass nicht alles automatisch vorzeitige Optimierung ist. – Mysticial

+0

Mit oder ohne Optimierungsflags? – Cornstalks

+0

ohne Flaggen – perreal

Verwandte Themen