(Ja, ich weiß, dass ein Maschinenbefehl normalerweise keine Rolle spielt. Ich stelle diese Frage, weil ich das Pimpl-Idiom verstehen und es auf die bestmögliche Weise verwenden möchte, und weil mir manchmal etwas wichtig ist Maschinenbefehl.)C++ pimpl idiom verschwendet eine Anweisung vs. C-Stil?
In dem folgenden Beispielcode gibt es zwei Klassen, Thing
und OtherThing
. Benutzer würden "thing.hh" einschließen. Thing
verwendet das Pimpl-Idiom, um seine Implementierung zu verbergen. OtherThing
verwendet einen C-Stil – Nicht-Member-Funktionen, die zurückgeben und Zeiger nehmen. Dieser Stil erzeugt einen etwas besseren Maschinencode. Ich bin Fragen: Gibt es eine Möglichkeit, C++ - Stil verwenden – dh, machen Sie die Funktionen in Elementfunktionen – und noch immer die Maschinenanweisung speichern. Ich mag diesen Stil, weil er den Namensraum außerhalb der Klasse nicht verschmutzt.
Hinweis: Ich sehe nur auf Aufruf von Mitgliedsfunktionen (in diesem Fall calc
). Ich betrachte die Objektzuordnung nicht.
Unten sind die Dateien, Befehle und der Maschinencode auf meinem Mac.
thing.hh:
class ThingImpl;
class Thing
{
ThingImpl *impl;
public:
Thing();
int calc();
};
class OtherThing;
OtherThing *make_other();
int calc(OtherThing *);
thing.cc:
#include "thing.hh"
struct ThingImpl
{
int x;
};
Thing::Thing()
{
impl = new ThingImpl;
impl->x = 5;
}
int Thing::calc()
{
return impl->x + 1;
}
struct OtherThing
{
int x;
};
OtherThing *make_other()
{
OtherThing *t = new OtherThing;
t->x = 5;
}
int calc(OtherThing *t)
{
return t->x + 1;
}
main.cc (nur den Code zu testen, tatsächlich funktioniert ...)
#include "thing.hh"
#include <cstdio>
int main()
{
Thing *t = new Thing;
printf("calc: %d\n", t->calc());
OtherThing *t2 = make_other();
printf("calc: %d\n", calc(t2));
}
Makefile:
all: main
thing.o : thing.cc thing.hh
g++ -fomit-frame-pointer -O2 -c thing.cc
main.o : main.cc thing.hh
g++ -fomit-frame-pointer -O2 -c main.cc
main: main.o thing.o
g++ -O2 -o [email protected] $^
clean:
rm *.o
rm main
Führen Sie make
aus und sehen Sie sich den Maschinencode an. Auf dem Mac verwende ich otool -tv thing.o | c++filt
. Auf Linux denke ich, es ist objdump -d thing.o
. Hier ist der relevante Ausgang:
Thing :: Calc():
0000000000000000 movq (% rdi)% rax
0000000000000003 movl (% rax),% eax
0000000000000005 inkl% eax
0000000000000007 ret
calc (OtherThing *):
0000000000000010 movl (% RDI),% eax
0000000000000012 inkl% eax
0000000000000014 ret
Beachten Sie die zusätzliche Anweisung wegen der Zeigerindirektion. Die erste Funktion sucht zwei Felder (impl, dann x), während die zweite nur x erhalten muss. Was kann getan werden?
Laufen Sie mit voller Optimierung? –
@the_drow: Schauen Sie sich das Makefile an. Und nein, ist er nicht. @Rob: Versuche mit '-O3' zu kompilieren ... irgendeinen Grund, warum du * nicht * die volle Optimierung benutzt? –
Sie * müssen * den Zeiger irgendwann dereferenzieren. Es kommt nicht herum. –