3

仮想関数呼び出しの最適化について質問があります。私はどこかで読んだことがあります(そして問題は今記事が見つからないことです)これに似た構造を使用することでv-tableルックアップを最適化できるかもしれません:

// Base.h
class Base
{
public:
    virtual void Foo() = 0;
};

// Concrete.h
class Concrete : public Base
{
public:
    virtual void Foo()
    {
        // do something;
    }
};

//Some.h
extern Base* const g_object;

// Some.cpp
Concrete on_stack_concrete;

Base* const g_object = &on_stack_concrete;

トリックは、スタック上で(動的にではなく)割り当てられた変数へのconstポインターを使用し、コンパイラーがそれを最適化することを想定しています。したがって、ユーザーがg_object-> Foo()を呼び出すと、//do何かの部分がv-tableルックアップを必要とせずに実行されます。

それは本当ですか?

リプレイをよろしくお願いします。

編集:

このような構成の可能な使用法は、具体的な実装のインターフェースを制限することです。もちろん、「制限された」メソッドはプライベートである必要があると主張することもできますが、ライブラリの他のモジュールは、ユーザーがそれらを操作できるようにすることなく、オブジェクトのパブリック追加メソッドにアクセスする必要がある場合があります。したがって、たとえば#definesを使用すると、次のようなコードを作成できます。

// Some.cpp
#ifdef _WIN32
Win32Concrete concrete;
#elif defined _UNIX
UnixConcrete concrete;
#endif

Base* const g_global = &concrete;

実際、これらのクラスの宣言はCPPファイルでのみ定義できるため、ユーザーはそれらの存在に気づきません。

問題は、そもそもなぜそのような定数ポインタを使用するのかではなく、そのようなシナリオでvテーブルルックアップを最適化できるかどうかです。

4

3 に答える 3

4

を悪用しているようですvirtual

virtual実行時ポリモーフィズムを実装します。そして、あなたが説明するシナリオでは、それを使用または必要としません。コンパイル環境にWin32Concreteとの両方が存在することはほとんどありません。UnixConcrete

それ以外の:

// Some.cpp
#ifdef _WIN32
Win32Concrete concrete;
#elif defined _UNIX
UnixConcrete concrete;
#endif

Base* const g_global = &concrete;

使用する:

// CommonHeader.h
#ifdef _WIN32
typedef Win32Concrete Concrete;
#elif defined _UNIX
typedef UnixConcrete Concrete;
#endif

これで、関数は仮想である必要がなくなりました。

于 2012-09-22T12:54:12.847 に答える
2

これは、Doom 3 ソース コード ( https://github.com/id-Software/DOOM-3-BFG/ ) で使用されているアプローチです。たとえば、neo/framework/FileSystem.h では次のように定義されています。

extern idFileSystem *       fileSystem;

そして neo/framework/FileSystem.cpp はこれを定義します:

idFileSystemLocal   fileSystemLocal;
idFileSystem *      fileSystem = &fileSystemLocal;

私が見つけた唯一の議論はこれです:http://fabiensanglard.net/doom3/

idTech4 の高レベル オブジェクトはすべて、仮想メソッドを持つ抽象クラスです。各仮想メソッド アドレスは、実行時に呼び出す前に vtable で検索する必要があるため、通常、これにはパフォーマンス ヒットが伴います。しかし、それを避けるための「コツ」があります。

データ セグメントに静的に割り当てられたオブジェクトには既知の型があるため、commonLocal メソッドが呼び出されると、コンパイラは vtable ルックアップを最適化できなくなります。

于 2016-10-21T08:28:12.203 に答える
1

これを解決する最も簡単な方法は、制限されたメソッドへのアクセスが必要なクラスを Concrete クラスのフレンドにすることです。その後、彼らはクラスへのフル アクセスを取得し、他のすべての人はパブリック アクセスのみを取得します。

それが現実的でない場合は、すべての制限されたメソッドを保護して実装を基本クラスに配置し、保護されたメソッドを公開する特別なクラスを派生させることができます。

class Concrete
{
public:
    void foo() { ... }
protected:
    void bar() { ... }
};

class ConcretePrivate : public Concrete
{
public:
    void bar() { Concrete:: bar(); }
};

ConcretePrivate g_globalPrivate;
Concrete& g_global = g_globalPrivate;

を使用するコードはg_global、具象メソッドのみにアクセスできます。を使用するコードは、g_globalPrivateConcretePrivate メソッドにアクセスできます。

于 2012-09-22T13:32:13.847 に答える