10

最近、いくつかのクラスを書いています。そして、それが悪い習慣なのか、パフォーマンスが悪いのか、カプセル化を壊すのか、それともヘッダー内でいくつかの小さなメンバー関数を実際に定義することに本質的に悪いことが他にあるのかと思っていました(私はGoogleを試しました!)。これは、私がこれをたくさん使って書いたヘッダーの例です。

class Scheduler {
public:
    typedef std::list<BSubsystem*> SubsystemList;

    // Make sure the pointer to entityManager is zero on init
    // so that we can check if one has been attached in Tick()
    Scheduler() : entityManager(0) { }

    // Attaches a manager to the scheduler - used by Tick()
    void AttachEntityManager( EntityManager &em )
        { entityManager = &em; }

    // Detaches the entityManager from a scheduler.
    void DetachEntityManager()
        { entityManager = 0; }

    // Adds a subsystem to the scheduler; executed on Tick()
    void AddSubsystem( BSubsystem* s )
        { subsystemList.push_back(s); }

    // Removes the subsystem of a type given
    void RemoveSubsystem( const SubsystemTypeID& );

    // Executes all subsystems
    void Tick();

    // Destroys subsystems that are in subsystemList
    virtual ~Scheduler();
private:
    // Holds a list of all subsystems
    SubsystemList subsystemList;

    // Holds the entity manager (if attached)
    EntityManager *entityManager;
};

では、このような関数のインライン化に本当に問題があるのでしょうか、それとも許容できるのでしょうか?

(また、これが「コードレビュー」サイトに適しているかどうかもわかりません)

4

7 に答える 7

11

インライン化により結合が増加し、クラス定義の「ノイズ」が増加するため、クラスが読みにくく、理解しにくくなります。原則として、インライン化は最適化の手段と見なされるべきであり、プロファイラが必要であると判断した場合にのみ使用してください。

いくつかの例外があります。他のすべての関数が純粋な仮想関数である場合は、抽象基底クラスの仮想デストラクタを常にインライン化します。空のデストラクタのためだけに別のソース ファイルを用意するのはばかげているように思われます。また、他のすべての関数が純粋な仮想関数であり、データ メンバーがない場合、デストラクタは他に何かを変更しない限り変更されません。また、"構造" (すべてのデータ メンバーがパブリックで、他の関数がないクラス) のインライン コンストラクターを提供することもあります。また、ヘッダーではなくソース ファイルで定義されているクラスでインライン化を避けることについても、あまり厳密ではありません。その場合、カップリングの問題は明らかに当てはまりません。

于 2011-08-01T08:17:12.507 に答える
6

あなたのメンバー関数はすべてワンライナーなので、私の意見ではそれは受け入れられます。インライン関数は、実際にはコード サイズを縮小する可能性があることに注意してください(!!)。これは、最適化コンパイラが (非インライン) 関数をブロックに収まるようにサイズを大きくするためです。

コードを読みやすくするために、次のようにインライン定義を使用することをお勧めします。

class Scheduler
{
    ...

    void Scheduler::DetachEntityManager();

    ...
};


inline void Scheduler::DetachEntityManager()
{
    entityManager = 0;
}

私の意見では、その方が読みやすいです。

于 2011-08-01T07:44:26.400 に答える
2

インライン化 (私の理解が正しければ、コンパイラの動作ではなく、単純なコードをヘッダー ファイルに直接書き込む習慣を意味します) は、次の 2 つの要因によって読みやすさを向上させると思います。

  1. 自明な方法と自明でない方法を区別します。
  2. 自己文書化コードであるため、簡単なメソッドの効果が一目でわかります。

設計の視点からは、それはあまり重要ではありません。subsystemList メンバーを変更せずにインライン メソッドを変更することはありません。どちらの場合も再コンパイルが必要です。メソッドはパブリック インターフェイスを持つメソッドであるため、インライン化はカプセル化に影響しません。

そのため、メソッドが、長いドキュメントを必要としない、またはインターフェイスの変更を含まない変更の必要性が考えられるような単純なワンライナーである場合は、インライン化することをお勧めします。

于 2011-08-01T07:46:06.633 に答える
1

実行可能ファイルのサイズが大きくなり、場合によってはパフォーマンスが低下します。

インライン メソッドでは、それを使用する人がソース コード (つまり、ヘッダー内のコード) を表示できる必要があることに注意してください。これは、インライン メソッドの実装を少し変更すると、ヘッダーを使用するすべてのものが再コンパイルされることを意味します。インライン メソッドが定義されました。

一方で、これはパフォーマンスのわずかな向上です。メソッド呼び出しの一般的なオーバーヘッドを節約できるため、非常に頻繁に呼び出される短いメソッドに適しています。

インライン メソッドは、それらを使用する場所を知っていて、スパムしない場合は問題ありません。

編集:スタイルとカプセル化に関して、インライン メソッドを使用すると、コードがヘッダーにあるため、実装へのポインター、前方宣言などを使用できなくなります。

于 2011-08-01T07:37:28.610 に答える
1

インライン化には、少なくとも 3 つの「欠点」があります。

  1. インライン関数は、virtual キーワードと対立しています (概念的には、IMO を意味します。関数呼び出しをコードの一部に置き換えるか、関数呼び出しを仮想、つまりポリモーフィックにするかのいずれかです。とにかく、thisも参照してください。実際にいつ意味をなすかについての詳細);

  2. バイナリ コードが大きくなります。

  3. クラス定義にインライン メソッドを含めると、実装の詳細が明らかになります。

それとは別に、メソッドをインライン化することは明らかに問題ありませんが、最新のコンパイラは、パフォーマンスに意味がある場合、独自にメソッドをインライン化するのに十分スマートであることも事実です。ある意味、コンパイラに任せたほうがいいと思うのですが…。

于 2011-08-01T07:39:48.430 に答える
0

実際、すべての関数をヘッダー ファイルに書き込むことができます。関数が大きすぎる場合、コンパイラは関数を自動的にインライン展開しません。関数本体を最も適していると思われる場所に記述するだけで、コンパイラーに決定させます。関数のinline使用または同様のものをインライン化することを本当に主張する場合、キーワードも無視されることがよくあります__forceinline(これはMS固有だと思います)。

于 2011-08-01T08:19:56.557 に答える
0

body内のメソッドclassは通常inline自動的に実行されます。また、inline命令ではなく提案です。inlineコンパイラは一般に、関数かどうかを判断するのに十分賢いです。

この同様の質問を参照できます。

于 2011-08-01T07:41:33.237 に答える