从静态变量引用非静态变量会使非静态变量在静态变量之前析构
Referencing non-static variables from a static variable makes non-static variables destruct before static variable
简单地说:我想在我的程序退出时写入文件,所以我有一个对象接受文件名 (char*) 和对 Google Protobuf 消息的引用(出于这些目的,您可以在构造函数中假装它是一个字符串&),然后在析构函数中将消息写入文件名。然后,在 main() 中,我初始化了这些对象之一并将其声明为静态的(因此当程序出于任何原因退出时它将被破坏)。
在我更改一些(看似)不相关的内容之前,我的代码在多次修订后一直运行良好,但现在它不起作用了。现在,当对象析构时,char* 和引用都指向 char 和 Message 的未初始化版本。我有下面的相关代码:
using namespace std;
class WriteOnShutdown {
private:
const char* filename;
public:
MathHelper::Log& message;
WriteOnShutdown(char* a, MathHelper::Log& b) : filename(a), message(b) {}
~WriteOnShutdown() {
cout << "debug\n";
//*filename is -52 (unitialised char)
//READ ACCESS VIOLATION - message is still valid, but message.DebugString tries to call a pointer which hasn't been initialised yet
cout << message.DebugString() << endl;
}
};
int main() {
char filename[100];
MathHelper::Log log;
//Initialise filename and log
static WriteOnShutdown write(filename, log);
//Do program stuff here
//Then, at the end of main(), printing write.message.DebugString() works like a charm
cout << endl << write.message.DebugString();
_getch();
}
这称为 static initialization order fiasco(同样适用于析构函数)。一直都是问题,只是运气早点而已。
解决您的问题的一个简单方法是将 const char* filename;
更改为 std::string &filename;
并将 MathHelper::Log& message;
更改为 MathHelper::Log message;
。这样,在调用析构函数时内存仍然存在。
您遇到问题的原因如下:
MathHelper::Log log
将在 之前 您的主要 returns 被销毁,但 WriteOnShutdown
的析构函数将被调用 之后 主要returns.
由于 WriteOnShutdown
在析构函数中使用对 log
的引用,您正在访问 'dangling' 引用,调用未定义的行为,因此看到了问题。
你也遇到了与 filename
完全相同的问题。
明显的解决方法是将 write
(顺便说一句,由于多种原因,它是一个糟糕的对象名称)从静态变量更改为自动变量。
简单地说:我想在我的程序退出时写入文件,所以我有一个对象接受文件名 (char*) 和对 Google Protobuf 消息的引用(出于这些目的,您可以在构造函数中假装它是一个字符串&),然后在析构函数中将消息写入文件名。然后,在 main() 中,我初始化了这些对象之一并将其声明为静态的(因此当程序出于任何原因退出时它将被破坏)。
在我更改一些(看似)不相关的内容之前,我的代码在多次修订后一直运行良好,但现在它不起作用了。现在,当对象析构时,char* 和引用都指向 char 和 Message 的未初始化版本。我有下面的相关代码:
using namespace std;
class WriteOnShutdown {
private:
const char* filename;
public:
MathHelper::Log& message;
WriteOnShutdown(char* a, MathHelper::Log& b) : filename(a), message(b) {}
~WriteOnShutdown() {
cout << "debug\n";
//*filename is -52 (unitialised char)
//READ ACCESS VIOLATION - message is still valid, but message.DebugString tries to call a pointer which hasn't been initialised yet
cout << message.DebugString() << endl;
}
};
int main() {
char filename[100];
MathHelper::Log log;
//Initialise filename and log
static WriteOnShutdown write(filename, log);
//Do program stuff here
//Then, at the end of main(), printing write.message.DebugString() works like a charm
cout << endl << write.message.DebugString();
_getch();
}
这称为 static initialization order fiasco(同样适用于析构函数)。一直都是问题,只是运气早点而已。
解决您的问题的一个简单方法是将 const char* filename;
更改为 std::string &filename;
并将 MathHelper::Log& message;
更改为 MathHelper::Log message;
。这样,在调用析构函数时内存仍然存在。
您遇到问题的原因如下:
MathHelper::Log log
将在 之前 您的主要 returns 被销毁,但 WriteOnShutdown
的析构函数将被调用 之后 主要returns.
由于 WriteOnShutdown
在析构函数中使用对 log
的引用,您正在访问 'dangling' 引用,调用未定义的行为,因此看到了问题。
你也遇到了与 filename
完全相同的问题。
明显的解决方法是将 write
(顺便说一句,由于多种原因,它是一个糟糕的对象名称)从静态变量更改为自动变量。