以下のコードは、予想される(また間違いなく直感的な)動作を示しています。 main()
が入力される前に実行可能ファイルの静的オブジェクトが初期化されるのと同様に、動的にロードされるライブラリの静的オブジェクトは、dlopen()
が返される前に初期化されることが予想されます。dlopen()が返す前に、動的にロードされたライブラリの静的C++オブジェクトが初期化されていますか?
問題点:ランタイムにロードされたライブラリの動作は何らかの形で保証されていますか、それとも便利な事故やラッキーな実装の詳細なのでしょうか?呼び出し中のライブラリ内の静的オブジェクトのコンストラクタを使用することができますか?呼び出しの範囲内でいくつかの望ましい動作を保証するために、__attribute__((constructor))
とマークされた関数のような代替手段に頼らなければなりませんか?
// libtest.cpp
#include <iostream>
namespace
{
class Test
{
public:
Test() { std::cerr << "In Test()...\n"; }
~Test() { std::cerr << "In ~Test()...\n"; }
};
Test test; // when is this initialized?
}
// testso.cpp
#include <dlfcn.h>
#include <iostream>
int main(int ac, char* av[])
{
if (ac < 2)
{
std::cerr << "Usage: " << av[0] << "library-name\n";
return 1;
}
std::cerr << "Before dlopen()...\n";
::dlerror();
void* _handle(::dlopen(av[1], RTLD_NOW));
std::cerr << "After dlopen()...\n";
if (!_handle)
{
std::cerr << "Error: " << ::dlerror() << ", exiting...\n";
return 2;
}
::dlclose(_handle);
std::cerr << "After dlclose()...\n";
return 0;
}
コンパイルと実行(dlopen()
戻る前Test()
呼び出しに注意してください):
$ g++ -o libtest.so -shared -fPIC libtest.cpp
$ g++ -o testso -ldl testso.cpp
$ ./testso ./libtest.so
Before dlopen()...
In Test()...
After dlopen()...
In ~Test()...
After dlclose()...
$
を。最初
おそらく、http://stackoverflow.com/questions/19373061/what-happens-to-global-and-static-variables-in-a-shared-library-when-it-is-dynamの複製ですか? –
最初のヒント: '__attribute __((コンストラクタ))'を使わないでください。それを避けることができます。これは一般的にハックとみなされ、移植性がありません。代わりにエクスポートされた関数を使用してください。その義務的な警告ラベルをそこに投げるだけです。 – Qix
エクスポートされた関数を外部から呼び出す必要があります。コンストラクタールーチンは自動的に実行されますが、外部の操作は必要ありません(ライブラリー自体の負荷を引き出す以外)。後者の動作が必要な場合、問題は静的オブジェクトのコンストラクタがこれを満たすことができるかどうかです。 「コンストラクタ関数」は、コンストラクタのコンセプトをネイティブに持たないCなどの言語用です。 – arayq2