GCC __attribute__((constructor)) 在对象构造函数之前调用
Posted
技术标签:
【中文标题】GCC __attribute__((constructor)) 在对象构造函数之前调用【英文标题】:GCC __attribute__((constructor)) is called before object constructor 【发布时间】:2018-06-05 08:27:20 【问题描述】:在我的共享库中,我需要将一些数据加载到 unordered_map 中,并尝试在标记为 __attribute__((constructor)) 的函数中执行此操作。但是,我在每次地图操作中都获得了 SIGFPE。在查看了***之后,我发现这意味着 unordered_map 未初始化。这对我来说是非常出乎意料和无法理解的,因为乍一看,它违反了 C++ 合同。任何人都可以帮助我在构造函数运行后如何运行这个方法?这是我自己的构造函数的一个工作示例,它表明它没有被调用:
#include <stdio.h>
class Ala
int i;
public:
Ala()
printf("constructor called\n");
i = 3;
int getI()
return i;
;
Ala a;
__attribute__((constructor))
static void initialize_shared_library()
printf("initializing shared library\n");
printf("a.i=%d\n", a.getI());
printf("end of initialization of the shared library\n");
结果是
initializing shared library
a.i=0
end of initialization of the shared library
constructor called
但是,如果尝试使用 std::cout 而不是 printfs,那么它会立即进入 SEGFAULTs(因为流的构造函数没有运行)
【问题讨论】:
您可以尝试使用__attribute__((init_priority(123)) 语法,并为a
提供比此函数小的数字
您需要指定优先级以确保构造函数的正确顺序。最好远离编译器扩展,并按照答案中的建议使用 vanilla c++ 构造。
“它违反了 C++ 合同”:当然,它违反了 C++ 合同;当然您使用了编译器扩展——这意味着它不会像标准 C++ 那样运行。您需要阅读扩展的文档以了解其行为方式。
@MartinBonner 不幸的是,文档似乎很老套,它不包括诸如与没有该属性的全局对象的交互等内容
我认为这里发生的事情的顺序是不确定的。它当然似乎没有记录在案。这是一个旧线程,但请参阅:***.com/questions/8433484/…
【参考方案1】:
__attribute__((constructor))
是编译器扩展,因此您离开了标准 C++ 领域。看起来 GCC 的构造函数是在全局初始化之前运行的。
修复它的方法是使用另一个 vanilla C++ 构造,例如一个全局对象,其初始化通过在与其他全局相同的 TU 中定义它来正确排序:
Ala a;
static void initialize_shared_library()
printf("initializing shared library\n");
printf("a.i=%d\n", a.getI());
printf("end of initialization of the shared library\n");
static int const do_init = (initialize_shared_library(), 0);
【讨论】:
可以将其表述为static struct init init() /* do init */ force_init;
- 这避免了有点棘手的逗号运算符。【参考方案2】:
如果您使用返回静态局部变量的函数,该变量将在函数第一次被调用时被初始化。 见:When do function-level static variables get allocated/initialized?
struct Ala
// Your code here
static Ala& get_singleton();
;
Ala& Ala::get_singleton()
static Ala singleton;
return singleton;
static void initialize_shared_library()
Ala& a = get_singleton();
printf("initializing shared library\n");
printf("a.i=%d\n", a.getI());
printf("end of initialization of the shared library\n");
正如其他人所说,通常最好将所有初始化过程封装在一个对象中,让构造函数为你完成工作(构造函数的主体在类的所有成员都初始化后执行)。
【讨论】:
【参考方案3】:如果您只想在 a
初始化后运行某些东西,有几种方法可以在不离开标准 C++ 的情况下执行此操作;这是一个:
struct Ala2 : Ala
Ala2()
// your init code here
;
Ala2 a;
【讨论】:
以上是关于GCC __attribute__((constructor)) 在对象构造函数之前调用的主要内容,如果未能解决你的问题,请参考以下文章
等效于 Visual C++ 中 gcc 的 __attribute__ 格式
GCC __attribute__((constructor)) 在对象构造函数之前调用