我试图编写一个类来包装Boost记录器以便记录widechar。
问题是如果Logger被定义为 const成员引用,那么它会抛出异常'无法转换字符编码',否则它可以正常工作。
我在Visual Studio C ++中的Logger构造函数中添加了一个断点,在' Call Stack'窗口,它显示呼叫由
启动ConsoleApplication1.exe!`'记录器的动态初始化程序'()
所以问题是,如果定义为 const成员参考,会有什么不同?
这是一个最简单的例子:
#include "stdafx.h"
#include <iostream>
#include <boost/locale/generator.hpp>
#include <boost/log/common.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/console.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/sources/logger.hpp>
#include <boost/log/trivial.hpp>
namespace logging = boost::log;
namespace sinks = boost::log::sinks;
namespace attrs = boost::log::attributes;
namespace src = boost::log::sources;
namespace expr = boost::log::expressions;
namespace keywords = boost::log::keywords;
class Logger {
public:
static const Logger& GetInstance() {
static Logger logger;
return logger;
}
void Log(const std::wstring& message) const {
src::wseverity_logger< logging::trivial::severity_level > slg;
BOOST_LOG_SEV(slg, logging::trivial::error) << message;
}
private:
Logger() {
auto sink = logging::add_file_log(keywords::file_name = "sample.log");
std::locale loc = boost::locale::generator()("en_US.UTF-8");
sink->imbue(loc);
logging::add_common_attributes();
}
};
// *** The problem is introduced by line below ***
// *** If this line is removed, the logging doesn't throw exception. ***
const Logger& logger = Logger::GetInstance();
int main(int argc, char* argv[]) {
try {
Logger::GetInstance().Log(L"中文");
}
catch (const std::exception& e) {
std::cout << e.what() << std::endl;
}
return 0;
}
答案 0 :(得分:0)
问题基本上是static initialization order fiasco。
记录器有两种可能的首次初始化:
const Logger& logger = Logger::GetInstance(); // <== (a)
int main(int argc, char* argv[]) {
try {
Logger::GetInstance().Log(L"中文"); // <== (b)
(b)
发生在main之后,因此保证在所有pre main()
初始化发生后运行。 (a)
没有这样的保证,并且与其他潜在的静态初始化无关。似乎发生的事情是Logger::Logger()
中的某些东西依赖于已经初始化的另一个对象 - 但这还没有发生。