【发布时间】:2017-02-28 04:00:17
【问题描述】:
下面的代码演示了预期的(并且可以说是直观的)行为。正如在输入main() 之前初始化可执行文件中的静态对象一样,人们会期望在dlopen() 返回之前初始化动态加载的库中的静态对象。
问题:在运行时加载的库的这种行为是否以任何方式得到保证,还是只是一个方便的意外或幸运的实现细节?我们是否可以依赖被调用的库中静态对象的构造函数,或者我们是否必须求助于诸如标有__attribute__((constructor)) 的函数之类的替代方法,以确保在dlopen() 调用范围内实现某些期望的行为?
// 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;
}
编译并运行(注意Test() 调用之前dlopen() 返回):
$ 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()...
$
。
【问题讨论】:
-
第一个提示:不要使用
__attribute__((constructor))如果可以避免。它通常被认为是一种 hack 并且不可移植。请改用导出的函数。只是把那个强制性的警告标签扔在那里。 -
必须从外部调用导出的函数;而构造函数例程是自动运行的,实际上不需要任何外部操作(除了启动库本身的负载)。当需要后一种行为时,问题是静态对象的构造函数是否可以实现这一点。然后,“构造函数”将适用于 C 等本身没有构造函数概念的语言。
标签: c++