私は本物の C++ 初心者なので、しばらくお待ちください。まずは舞台を整えます。
binary.cpp
次のようなバイナリにコンパイルされるC++ ソースがあります。
# include "lotsofheaders.h"
int main(int argc, char* argv[])
{
int errorcode = FOOBAR_GLOBAL_UNKNOWN;
// foobar instanciation
Foobar foobar();
// multiple calls to :send_auth passing in foobar instance
errorcode = send_auth(getX(), getY(), foobar);
errorcode = send_auth(getX(), getY(), foobar);
errorcode = send_auth(getX(), getY(), foobar);
return errorcode == FOOBAR_OK ? EXIT_SUCCESS : EXIT_FAILURE;
}
メソッドは別のsend_auth
オブジェクト コード ファイルから読み込まれ、foobar のインスタンスが渡されます。その理由は、Foobar は、私がソースを持っておらず、複数回インスタンス化してはならない API オブジェクトから来ているからです。
main は 1 回だけ呼び出されるため、すべてが期待どおりに機能します。Foobar のインスタンスは 1 つだけで、send_auth
複数回呼び出すことができます。
バイナリは私には役に立ちません。同じことを行う共有オブジェクト ライブラリが必要です。Foobar のインスタンスを 1 つだけ作成send_with_auth
し、共有オブジェクト ライブラリが読み込まれた後に複数回呼び出すことができる外部インターフェイス メソッドを公開します。
私のライブラリコードはlibrary.cpp
次のようになります。
# include "lotsofheaders.h"
# include "library.h"
const char* send_with_auth(const char* X, const char* Y){
std::string x(X);
std::string y(Y);
int result = send_auth(x, y, 'some Foobar singleton');
return true;
}
Ruby FFI を介して共有オブジェクト ライブラリをロードするので、ライブラリに C スタイルのヘッダーがいくつか必要ですlibrary.h
。
extern "C" {
const char* send_with_auth(const char* X, const char* Y);
}
ステージ セットを使用して、ライブラリ内で Foobar のインスタンスを 1 回だけ作成し、それを のすべての呼び出しに渡してsend_auth
、Foobar からメモリ違反エラーが発生しないようにする必要があります。
これは、私が理解したシングルトンを使用した(非常に複雑な)試みです。library.h
次のような新しいものがあります:
extern "C" {
class Singleton
{
private:
static bool instanceFlag;
static Singleton *single;
Singleton()
{
//private constructor
}
public:
static Foobar* fo;
static Singleton* getInstance();
~Singleton()
{
instanceFlag = false;
}
};
const char* send_with_auth(const char* X, const char* Y);
}
そして、この実装がありますlibrary.cpp
:
# include "lotsofheaders.h"
# include "library.h"
bool Singleton::instanceFlag = false;
Singleton* Singleton::single = NULL;
Singleton* Singleton::getInstance()
{
if(! instanceFlag)
{
single = new Singleton();
instanceFlag = true;
// bringing up my Foobar instance once and only once
Foobar fo;
single->fo = &fo;
return single;
}
else
{
return single;
}
}
const char* send_with_auth(const char* X, const char* Y){
std::string x(X);
std::string y(Y);
Singleton *single;
single = Singleton::getInstance();
int result = send_auth(x, y, *single->fo);
return true;
}
このコードは少なくともコンパイルされ、すべてを共有オブジェクト ライブラリにバインドできます。そのライブラリを外部プロセス (私の場合は Ruby FFI を使用する Ruby モジュール) にロードすると、常にエラーが発生します。
Could not open library '/some/path/libfoobar.so': /some/path/libfoobar.so: undefined symbol: _ZN9Singleton2erE (LoadError)
library.o から libfoobar.so への私のコンパイル/バインディング/ストリッピング プロセスは問題ないと確信しています。他のケースでは成功するからです。ここで C++ のシングルトンの概念を誤解していると確信しています。共有オブジェクト ライブラリ内に Foobar のインスタンスを 1 つだけ作成し、それをライブラリが外部に公開する唯一のメソッドのすべての呼び出しに渡すという目標を達成するにはどうすればよいでしょうか。
誰でもそれを助けることができますか?よろしくフェリックス
アップデート
ライブラリで CommandlineParser を使用するのはばかげていました。実際には、単純に 2 つの C 文字列を返しました。API ライブラリ パスとログ ディレクトリ。それで、名前空間を再作成しました:
namespace
{
char* home("/path/to/api/libs");
char* log("/tmp");
Foobar foobar(home, log);
}
これにより、ライブラリをロードした瞬間にセグ フォールトが発生します。それとは対照的に、これらの行を関数に直接入れることができます。
const char* send_with_auth(const char* X, const char* Y){
std::string x(X);
std::string y(Y);
char* home("/path/to/api/libs");
char* log("/tmp");
Foobar foobar(home, log);
int result = send_auth(x, y, &foobar);
return true;
}
send_with_auth
への 2 回目の呼び出しですべてがクラッシュし、Foobar が再度インスタンス化されるという事実を除いて、ここではすべて正常に動作します。
更新 2:
最後に、さらに簡単に解決し、グローバルに利用可能な bool スイッチを使用して Foobar インスタンスを 1 回だけ初期化しました。
namespace baz{
bool foobarInitialized = false;
}
const char* send_with_auth(const char* certificatePath, const char* certificatePin, const char* xmlData){
std::string certificate_path(certificatePath);
std::string certificate_pin(certificatePin);
std::string xml_data(xmlData);
Foobar *foobar_ptr;
if (! baz::foobarInitialized) {
char* home_dir("/path/to/api/lib");
char* log_dir("/tmp");
foobar_ptr = new Foobar(home_dir, log_dir);
baz::foobarInitialized = true;
}
int result = send_auth(x, y, foobar_ptr);
return xml_data.c_str();
}
send_with_auth
これで、Foobar を複数回インスタンス化することなく、際限なく呼び出すことができます。終わり!