指定不同访问器中静态本地的构造/销毁顺序

时间:2013-12-03 08:52:09

标签: c++ gcc initialization clang

我在cxa_finalize运行程序时遇到崩溃(这是一个程序,而不是一个库):

$ ./ac-test.exe 
Assertion failed: AcLock.cpp(54): AcLock
libc++abi.dylib: terminate called without an active exception
Abort trap: 6

断言/崩溃是由于对象和记录器之间的交互。记录器在对象之前被破坏,但对象使用记录器。因此,弹出断言或崩溃的互斥锁已被破坏(因此锁定记录器时pthread_mutex_lock失败的原因。)

我在Specifying Attributes of VariablesDeclaring Attributes of Functions上阅读了GCC手册,但我显然遗漏了一些内容。

我将对象和记录器放在访问器中的公共头中,并尝试指定构造顺序:

// AcGlobals.h
static AcLogger& GetLogger() {

    static AcLogger logger __attribute__(init_priority(50));
    return logger;
}
static AcSocketList& GetAcceptSockets() {

    static AcSocketList sockets __attribute__(init_priority(100));
    return sockets;
}

这导致了一堆错误:

./AcGlobals.h:24:46: error: expected ';' at end of declaration
    static AcLogger logger __attribute__((init_priori...

./AcGlobals.h:24:47: warning: declaration does not declare anything
      [-Wmissing-declarations]
    static AcLogger logger __attribute__((init_priori...

我也尝试将属性放在函数而不是变量上:

// AcGlobals.h
static AcLogger& GetLogger() __attribute__(init_priority(50)) {

    static AcLogger logger;
    return logger;
}
static AcSocketList& GetAcceptSockets() __attribute__(init_priority(100)) {

    static AcSocketList sockets;
    return sockets;
}

这导致了更多问题:

./AcGlobals.h:22:53: warning: GCC does not allow init_priority attribute in this
      position on a function definition [-Wgcc-compat]
static AcLogger& GetLogger() __attribute__((init_priority(50))) {
                                              ^
./AcGlobals.h:22:53: error: can only use 'init_priority' attribute on file-scope
      definitions of objects of class type

我也尝试__attribute__((constructor(50)))代替init_priority而没有快乐。

注意:我正在使用Apple机器。 Apple有一个“功能”,其中构造函数优先级仅适用于同一文件中的装饰函数和变量。所以这些不能在翻译单位之间传播。

我究竟如何指定构造和销毁本地静态对象的顺序?

2 个答案:

答案 0 :(得分:3)

使用Meyers单身时,这是一个经典问题 (这基本上就是你在做什么)。解决方案是 破坏单身人士;而不是静态的本地 变量,你应该使用动态分配而不删除:

static  AcLogger& GetLogger()
{
    static AcLogger* logger = new AcLogger;
    return *logger;
}
注意,在这种情况下,您必须确保每次使用 记录器刷新(但这通常是这种情况); 否则,你可能会得到未刷新的数据。

关于您尝试使用您的扩展功能 编译器:我对它不太熟悉,但我不知道你是怎么回事 可以在局部变量上使用名为init_priority的东西。 局部静电的构造(和破坏)时间 变量是由语言定义的(在这种情况下,是 销毁时间你想要的东西)。如果你想使用 这个非标准的扩展,你可能不得不做 实例变量是静态类成员,甚至可能是全局变量 (在这种情况下,您不能将构造函数设为私有)。

答案 1 :(得分:1)

假设依赖是非循环的,您可以按照代码流进入函数的顺序利用初始化的标准行为,并按照初始化的相反顺序进行破坏。

换句话说,调用GetLogger()来初始化记录器,然后调用GetAcceptSockets()来初始化列表。这将导致套接字列表首先被破坏(当记录器仍然存在时),然后记录器最后被破坏。