(はい、通常は 1 つの機械語命令は問題にならないことを知っています。私がこの質問をするのは、pimpl のイディオムを理解し、可能な限り最良の方法で使用したいからです。また、1 つの機械語命令を気にすることもあるためです。 )
以下のサンプル コードには、 と の 2 つのクラスがThing
あり
OtherThing
ます。ユーザーは「thing.hh」を含めます。
Thing
pimpl イディオムを使用して実装を隠します。
OtherThing
C スタイル (ポインターを返したり受け取ったりする非メンバー関数) を使用します。このスタイルは、わずかに優れたマシン コードを生成します。私は疑問に思っています: C++ スタイルを使用する方法 (つまり、関数をメンバー関数にする方法) はありますか? クラス外の名前空間を汚染しないので、このスタイルが気に入っています。
注: メンバー関数の呼び出しのみを検討しています (この場合はcalc
)。オブジェクトの割り当ては見ていません。
以下は、私の Mac 上のファイル、コマンド、およびマシン コードです。
こと.hh:
class ThingImpl;
class Thing
{
ThingImpl *impl;
public:
Thing();
int calc();
};
class OtherThing;
OtherThing *make_other();
int calc(OtherThing *);
事.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));
}
メイクファイル:
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 :: calc(): 0000000000000000
MOVQ(%RDI)、%
RAX 00000000000003 MOVL(%RAX )、%EAX 0000000000000005 INPLECT EAX 0000000000000007 RET CALC(その他): 00000000000010 MOVL(%RDI) 0000000000000014 ret
ポインタの間接化による余分な命令に注意してください。最初の関数は 2 つのフィールド (impl、次に x) を検索しますが、2 番目の関数は x を取得するだけで済みます。何ができるでしょうか?