我最近在Visual C ++ 2010中编写了一个非常简单的logger类,但是我遇到了问题。每次运行程序时,都会出现调试断言失败。
Expression: _CrtIsValidHeapPointer(pUserData)
这就是我班级的样子(基本上只是从这里的答案C++ Singleton design pattern稍微修改一下):
class Logger
{
public:
// Returns static instance of Logger.
static Logger& getInstance()
{
static Logger logger; // This is where the assertion raises.
return logger;
}
void logError(std::string errorText);
// Destructor.
~Logger();
private:
std::ofstream logFileStream;
// The constructor is private to prevent class instantiating.
Logger();
// The copy constructor and '=' operator need to be disabled.
Logger(Logger const&) { };
Logger& operator=(Logger other) { };
};
构造函数是:
Logger::Logger()
: logFileStream(Globals::logFileName, std::ios_base::trunc)
{
// (Tries to open the file specified in Globals for (re)writing.)
}
我发现我可以通过某种方式使用静态变量或方法来解决它,但我不明白这段代码有什么问题。有谁知道,问题在哪里?
编辑:仅供参考,调用此代码时失败(第一次):
Logger::getInstance().logError("hello");
编辑2:这是logFileName
中Globals
的定义:
static const std::string logFileName = "errorLog.log";
答案 0 :(得分:1)
我的猜测是你从另一个全局变量的构造函数中调用getInstance()
,并遇到臭名昭着的初始化顺序fiasco - 未指定Globals::logFileName
是否已在其他全局变量之前初始化翻译单位。
一个解决方法是使用旧式C字符串,在调用任何全局构造函数之前将对其进行静态初始化:
static const char * logFileName = "errorLog.log";
另一种可能性是通过函数访问它:
static std::string logFileName() {return "errorLog.log";}
我最喜欢的解决方案是完全删除全局实例,并传递对它的任何需求的引用;但是有些人可能会觉得这很乏味,特别是如果你已经拥有大量使用全局的代码。
答案 1 :(得分:0)
C ++ / CLI不是标准的C ++,而是采用略有不同的规则。你在使用C ++ / CLI托管代码吗? (/ clr编译器选项?)当将C ++(非托管)代码与C ++ / CLI(托管)代码混合时,这看起来是一个常见问题。它与程序初始化和程序退出时托管和非托管构造和破坏的方式有关。删除析构函数对我有用 - 你能在Logger类中做到吗?
有关详细信息和可能的解决方法:
http://www.codeproject.com/Articles/442784/Best-gotchas-of-Cplusplus-CLI