我在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 Variables和Declaring 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有一个“功能”,其中构造函数优先级仅适用于同一文件中的装饰函数和变量。所以这些不能在翻译单位之间传播。
我究竟如何指定构造和销毁本地静态对象的顺序?
答案 0 :(得分:3)
使用Meyers单身时,这是一个经典问题 (这基本上就是你在做什么)。解决方案是 不破坏单身人士;而不是静态的本地 变量,你应该使用动态分配而不删除:
static AcLogger& GetLogger()
{
static AcLogger* logger = new AcLogger;
return *logger;
}
注意,在这种情况下,您必须确保每次使用
记录器刷新(但这通常是这种情况);
否则,你可能会得到未刷新的数据。
关于您尝试使用您的扩展功能
编译器:我对它不太熟悉,但我不知道你是怎么回事
可以在局部变量上使用名为init_priority
的东西。
局部静电的构造(和破坏)时间
变量是由语言定义的(在这种情况下,是
销毁时间不你想要的东西)。如果你想使用
这个非标准的扩展,你可能不得不做
实例变量是静态类成员,甚至可能是全局变量
(在这种情况下,您不能将构造函数设为私有)。
答案 1 :(得分:1)
假设依赖是非循环的,您可以按照代码流进入函数的顺序利用初始化的标准行为,并按照初始化的相反顺序进行破坏。
换句话说,调用GetLogger()来初始化记录器,然后调用GetAcceptSockets()来初始化列表。这将导致套接字列表首先被破坏(当记录器仍然存在时),然后记录器最后被破坏。