3

私はかなり大きな C++ サポート ライブラリを開発しており、ヘッダーのみのアプローチに移行していることに気付きました。C++ では、クラスで定義した場所を実装できるため、これはほとんど機能します。テンプレート化されたメソッドの場合、実装はとにかく同じファイルにある必要があるため、実装を定義とともに保持する方がはるかに簡単であることがわかりました。

ただし、「ソース」を使用しなければならない場合が数回あります。ほんの一例として、循環依存が発生することがあり、実装をクラス定義の外に記述する必要があります。これが私がそれをどのように扱っているかです:

//part of libfoo.h
class Bar
{
  void CircularDependency(void);
};

#ifdef LIBFOO_COMPILE_INLINE
void Bar::CircularDependency(void)
{
  //...
}
#endif

次に、libfoo を使用するプロジェクトは、main.cpp で次のことを行います。

//main.cpp
#define LIBFOO_COMPILE_INLINE
#include "libfoo.h"

その他の .cpp では:

//other.cpp
#include "libfoo.h"

ポイントは、compile-inline セクションが (main.cpp で) 1 回だけコンパイルされることです。

そして最後に私の質問: このイディオムまたはこのように機能する他のプロジェクトの名前はありますか? テンプレート化とクラスメソッドによって実装と定義がぼやけているのは当然の結果のようです。そして、これが悪い考えである理由や、うまくスケーリングできない可能性がある理由はありますか?

余談ですが、多くのコーダーは、正当な理由で、ヘッダーが実装ではなくインターフェイスに似ていることを好むことを知っていますが、プライベートメンバーをすべて一緒に隠すのが好きなので、IMHOドキュメントジェネレーターはインターフェイスの記述に適しています:-)

4

3 に答える 3

4

の定義がヘッダーに表示されるまでにinline循環依存の問題が解決されている場合は、キーワードを使用できるはずです。Bar::CircularDependency()libfoo.h

//part of libfoo.h
class Bar
{
  void CircularDependency(void);
};


// other stuff that 'resolves' the circular dependency
// ...
// ...

inline void Bar::CircularDependency(void)
{
  //...
}

これにより、ライブラリが使いやすくなります (ユーザーはLIBFOO_COMPILE_INLINE、ヘッダーが含まれる正確に 1 つの場所で定義する必要があるという事実に対処する必要はありません)。

于 2012-03-23T18:32:52.377 に答える
2

関数がインラインであるデカールを転送できるため、循環依存は実際には問題ではありません。ただし、これはあまりお勧めしません。「ソースレス」アプローチでは、最初はどこかからのライブラリを使用しやすくなりますが、コンパイル時間が長くなり、ファイル間の結合が緊密になります。巨大なソースベースでは、これは本質的に、妥当な時間でコードをビルドするためにホープを殺します。確かに巨大なのは数百万行のコードから始まりますが、誰が些細なプログラムを気にしますか...?(そして、はい、私が働いている場所では、数千万行のコードが単一の実行可能ファイルに組み込まれています)

于 2012-03-23T18:44:26.583 に答える
2

これが悪い考えである私の理由。

コンパイル時間の増加

ヘッダーを含むすべての個々のコンパイル ユニットは、ソース自体に加えて、すべてのヘッダー ファイルをコンパイルする必要があります。これにより、おそらくコンパイル時間が長くなり、小さな変更でコードをテストしているときにイライラする可能性があります. コンパイラがそれを最適化する可能性があると主張することもできますが、IMO はある点を超えて最適化できませんでした。

より大きなコード セグメント

すべての関数がインラインで記述されている場合、コンパイラは関数が呼び出される場所にすべてのコードを配置する必要があることを意味します。これはコード セグメントを破壊し、プログラムの読み込み時間に影響を与え、プログラムがより多くのメモリを消費します。

密結合でクライアント コードに依存関係を作成する

実装を変更するたびに、すべてのクライアントが更新される必要があります (コードを再コンパイルすることによって)。ただし、実装が独立した共有オブジェクト (.so または .dll) に配置されている場合、クライアントは新しい共有オブジェクトにリンクする必要があります。

また、なぜこれを行うのかわかりません。

//main.cpp
#define LIBFOO_COMPILE_INLINE
#include "libfoo.h"

これを行う必要がある場合は、実装コードを main.cpp 自体に入れるだけで済みます。とにかく、LIBFOO_COMPILE_INLINE は 1 つのコンパイル単位でのみ定義できます。そうしないと、定義が重複します。

私は実際、まとまりのあるテンプレート コードを書くためのイディオムを開発することに非常に興味があります。将来的には、C++ コンパイラはまとまりのあるテンプレートの記述をサポートする必要があります。これにより、テンプレートの実装が変更されるたびに、クライアントがコードを再コンパイルする必要がなくなるということです。

于 2012-03-23T18:50:02.937 に答える