( Да, я знаю, что одна машинная инструкция обычно не имеет значения. Я задаю этот вопрос, потому что хочу понять идиому pimpl и использовать ее наилучшим образом; и потому что иногда я делаю это забота об одной машинной инструкции. )
В приведенном ниже примере кода есть два класса, Thing
и
OtherThing
. Пользователи будут включать "thing.hh".
Thing
использует идиому pimpl, чтобы скрыть свою реализацию.
OtherThing
использует стиль C & ndash; функции, не являющиеся членами, которые возвращают и принимают
указатели. Этот стиль производит немного лучший машинный код. я
интересно: есть ли способ использовать стиль C ++ & ndash; т.е. сделать функции
в функции-члены & ndash; и все же еще сохраните машинную инструкцию. Мне нравится этот стиль, потому что он не загрязняет пространство имен вне класса.
Примечание: я смотрю только на вызов функций-членов (в данном случае calc
). Я не смотрю на распределение объектов.
Ниже приведены файлы, команды и машинный код на моем 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 (просто для проверки кода на самом деле работает ...)
#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 $@ $^
clean:
rm *.o
rm main
Запустите make
, а затем посмотрите на машинный код. На Mac я использую otool -tv thing.o | c++filt
. На Linux я думаю, что это objdump -d thing.o
. Вот соответствующий вывод:
Thing :: известково ():
0000000000000000 movq (% rdi),% rax
0000000000000003 movl (% rax),% eax
0000000000005000 вкл.% Eax
0000000000000007 рет
известково (OtherThing *):
0000000000000010 movl (% rdi),% eax
0000000000000012 вкл.% Eax
0000000000000014 рет
Обратите внимание на дополнительную инструкцию из-за косвенности указателя. Первая функция ищет два поля (impl, затем x), а вторая должна получить только x. Что можно сделать?