2016-07-05 14 views
0

ich vor kurzem erfahren, dass ich folgendes mit geben aa Struktur an eine Funktion in C tun können, ++:Effizienz einer Struktur an eine Funktion ohne eine lokale Variable Instanziierung

(Ich entschuldige mich für keinen passenderen Namen verwendet für können sie mich dieses „Feature“ in dem Titel, zu korrigieren)

#include <iostream> 

typedef struct mystruct{ 
    int data1; 
    int data2; 
} MYSTRUCT; 

void myfunction(MYSTRUCT _struct){ 
    std::cout << _struct.data1 << _struct.data2; 
} 

int main(){ 
    //This is what I recently learned 
    myfunction(MYSTRUCT{2,3}); 
    return 0; 
} 

das macht mir Wunder, ist dies weniger kostspielig als ein lokales MYSTRUCT Instanziieren und weitergeben als Wert an die Funktion? Oder ist es nur ein bequemer Weg, das Gleiche zu tun, nur dass die temporäre Variable gleich danach eliminiert wird?

Zum Beispiel das Hinzufügen dieser Zeile #define KBIG 10000000, ist dies:

std::vector<MYSTRUCT> myvector1; 
for (long long i = 0; i < KBIG; i++) { 
    myvector1.push_back(MYSTRUCT{ 1,1 }); 
} 

Konsequent schneller als das:

std::vector<MYSTRUCT> myvector2; 
for (long long i = 0; i < KBIG; i++) { 
    MYSTRUCT localstruct = { 1,1 }; 
    myvector2.push_back(localstruct); 
} 

ich es testen versucht, aber die Ergebnisse waren ziemlich inkonsistent, schwebt etwa 9-12 Sekunden für jeden. Manchmal wäre der erste schneller, manchmal nicht. Dies könnte natürlich auf alle Hintergrundprozesse zum Zeitpunkt des Testens zurückzuführen sein.

+0

Also ist die Schlussfolgerung, dass es keinen großen Leistungsunterschied gibt? Wenn Sie sicher wissen möchten, erstellen Sie mit aktivierter Optimierung und vergleichen Sie den generierten Code für beide Alternativen. –

Antwort

3

leicht Vereinfachen und Kompilieren zu Assembler:

extern void emit(int); 

typedef struct mystruct{ 
    int data1; 
    int data2; 
} MYSTRUCT; 

__attribute__((noinline)) 
void myfunction(MYSTRUCT _struct){ 
    emit(_struct.data1); 
    emit(_struct.data2); 
} 

int main(){ 
    //This is what I recently learned 
    myfunction(MYSTRUCT{2,3}); 
    return 0; 
} 

mit -O2 ergibt:

myfunction(mystruct): 
     pushq %rbx 
     movq %rdi, %rbx 
     call emit(int) 
     sarq $32, %rbx 
     movq %rbx, %rdi 
     popq %rbx 
     jmp  emit(int) 
main: 
     movabsq $12884901890, %rdi 
     subq $8, %rsp 
     call myfunction(mystruct) 
     xorl %eax, %eax 
     addq $8, %rsp 
     ret 

Was ist passiert?

Der Compiler hat festgestellt, dass die gesamte Struktur in ein Register passt und auf diese Weise übergeben wird.

Moral der Geschichte: ausdrückliche Absicht. Lassen Sie den Compiler sich um Details kümmern.

Wenn Sie eine Kopie benötigen, benötigen Sie eine Kopie. Ende der Geschichte.

1

Wenn die Geschwindigkeit von Bedeutung ist, nehmen Sie Messungen des Kopierens im Vergleich zur Aufnahme von const ref (d. H. const MYSTRUCT& _struct). Wenn Sie Messungen durchführen, stellen Sie sicher, dass Sie sie ausführen < 1> < 2>, dann < 2> < 1>, um Cache-Effekt zu kompensieren.

Vorschläge: Vermeiden Sie die Verwendung von _ als erstes Zeichen des Parameters, da einige reservierte Wörter damit beginnen; Struct auch nicht groß.

+0

falsch. Warum denken Sie, dass eine Referenz schneller ist? Sie wissen nicht, wie sich der Optimierer dem Code nähert. Der resultierende Assembler hat oft keine Ähnlichkeit mit dem Quellcode. –

+0

Bearbeitet: nehmen Sie Messungen statt nur const ref. Das heißt, es gibt einen Grund, warum wir const refs für reale Objekte nehmen (ich glaube, das Beispiel von OP war genau das - ein Beispiel, keine Kopie der tatsächlichen Struktur. Ich könnte hier falsch liegen - ein Kommentar von OP wäre sicherlich) hilf dabei, dies zu klären. Ich behaupte nicht, dass es * immer * schneller sein wird, nur dass es das erste wäre, was ich nach einer realen Struktur suche. – lorro

0

Wenn Sie Ihren Code beschleunigen wollen, empfehle ich Ihnen die Struktur über const Referenz zu übergeben, wie folgt:

void myfunction (const MYSTRUCT& _struct) 
{ 
    std::cout << _struct.data1 << _struct.data2; 
} 

Dieses viel schneller sein wird als denn durch Wert vorbei anstatt eine ganze kopieren struct, wird nur die Adresse übergeben.

(Ok, es wird nicht so viel Unterschied in diesem Fall sein, da Ihre Struktur nur zwei ganzen Zahlen enthält, aber es Sie haben> 1000 Bytes (zum Beispiel), dann wird es einen bemerkenswerten Unterschied)

Auch ich schlage vor, Sie std::vector<T>::emplace_back statt std::vector<T>::push_back

std::vector<MYSTRUCT> myvector1; 
for (long long i = 0; i < KBIG; i++) 
{ 
    myvector1.emplace_back (1, 1); 
} 

emplace_back leitet seine Argumente an den Konstruktor von mystruct, verwenden zu verwenden, damit der Compiler keine nutzlose Kopie erstellen.

+0

falsch. das ist nicht "viel schneller". Sie können nicht über die Optimierungen nachdenken, die der Compiler vornehmen wird. ausdrückliche Absicht und lass es dabei. –

+0

'Das wird wahrscheinlich schneller' ok? –

+0

Absolut nicht. –