web-dev-qa-db-ja.com

C ++共有オブジェクトに状態を保存するためのベストプラクティス

Cプログラムとインターフェイスする可能性のあるC++動的リンクライブラリ(つまり、共有オブジェクト)を開発する場合、エクスポートされた関数呼び出し全体でプログラムの状態を保存するためのベストプラクティスは何ですか?

私は経験の浅いC++プログラマーとして、次の方法を考えることができます。

  • コンパイル単位レベルのstatic変数。
  • 状態を保持し、各API呼び出しでそのアドレスをやり取りするstructをヒープでインスタンス化します(JNIのように)。

最初のアプローチの問題は、状態変数を初期化するためにいくつかのデータが必要であり、これらのデータがinit AP​​I(エクスポートされた関数の1つ)を呼び出すことによって提供されることです。反対に、モジュールのレベルstatic変数を使用する場合、これらの変数が初期化されているとき、それらのデータはまだ利用できません。

また、2番目の方法の私の問題は、各API関数にそのポインターを指定する必要があることです。これは少し面倒です。

static変数がそれらの状態変数にpointersであり、そのinit関数に割り当てられるという別のオプションがあることに注意してください(実際には、状態変数はinitとそのアドレスは、これらの静的変数に保存されます)。このオプションは問題ありませんが、可能な限りpointersを使用したくありません。

7
frogatto

状態オブジェクトへのポインターを渡すのがおそらく最良の解決策です。どうして?

関数のステートフル性が明示的かつ明白になります。これは、最も一般的で最も拡張可能なソリューションです。

残念ながら、(非表示の)グローバル状態を持つAPIはかなり一般的です。彼らは単純なものを単純にする傾向がありますが、より困難なものを完全に不可能にすることがよくあります。

例えば。データベースクライアントライブラリを想像してください。データベースにアクセスするには、最初に接続を作成する必要があります。複数のデータベースに同時に接続したい場合はどうなりますか?ライブラリに単一のグローバル接続が隠されている場合、これは完全に不可能です。

余分なパラメーターを渡すのはやや迷惑です。しかし、すべての状態が持ち運びが必要な単一のオブジェクトにグループ化されている限り、それはvery迷惑ではありません。

非表示のグローバル状態を保持することを決定したとしても、その状態を1つのオブジェクトにグループ化して、管理を容易にします。複数の関連するグローバル変数を追跡することは非常にエラーが発生しやすく、単一のグローバル変数が初期化されているかどうかを確認することははるかに簡単です。非表示のグローバル状態では、ユーザーエラーを防止するために、エクスポートされた各関数で状態が設定されているかどうかを確認する必要があることに注意してください。

11
amon