2013-07-18 67 views
0

我試圖使用#define指令和宏在我們的代碼中使用log4cxx進行封裝。代碼編譯,但運行時我得到訪問衝突,因爲我相信流對象沒有正確初始化。使用<<運算符和宏的log4cxx訪問異常

它試圖使log4cxx可插拔看起來像這樣的頭文件:

#ifdef USE_LOG4CXX 
#include "log4cxx/logger.h" 

#define LOG_DEBUG(msg) LOG4CXX_DEBUG(logger, msg) 
#define LOG_INFO(msg) LOG4CXX_INFO(logger, msg) 
#define LOG_WARN(msg) LOG4CXX_WARN(logger, msg) 
#define LOG_ERROR(msg) LOG4CXX_ERROR(logger, msg) 

#define LOGGER_DECL static const log4cxx::LoggerPtr logger 
#define LOGGER_INIT(source,name) const log4cxx::LoggerPtr source::logger = log4cxx::Logger::getLogger(#name); 
#else // use some other log method, e.g. stdout which worked fine 

.cpp文件不記錄是這樣的:

LOG_INFO("state(): " << old_state << " ==> " << new_state); 

預處理器擴展.cpp文件到:

{ if (logger->isInfoEnabled()) { ::log4cxx::helpers::MessageBuffer oss_; logger->forcedLog(::log4cxx::Level::getInfo(), oss_.str(oss_ << "state(): " << state_ << " ==> " << new_state), ::log4cxx::spi::LocationInfo("c:\\dev\\ezx-capi\\iserver-api\\iserver_client.cpp", __FUNCSIG__ , 190)); }}; 

old_state和new_state的數據類型是int

在運行時,該應用程序失敗上:

std::basic_ostream<char>& operator<<(CharMessageBuffer& os, const V& val) { 
    return ((std::basic_ostream<char>&) os) << val; 
} 

在調試程序,問題看起來像CharMessageBuffer對象具有未初始化的std::basic_streambuf部件,因此當它進入附加的價值,它死亡。 (我不知道這一點的解釋雖然)。

鑽一路下來,死在std::basic_ostream

_Myt& __CLR_OR_THIS_CALL operator<<(int _Val) 
    { // insert an int 
    ios_base::iostate _State = ios_base::goodbit; 
    const sentry _Ok(*this); // dies right here, in the constructor 

無論如何,我明白,這事做與我如何使用宏調用LOG4CXX。 (當我有沒有定義USE_LOG4FXX,所有的日誌報表打算std::cout它工作得很好。)

UPDATE

另外一個資料片 - 看來,當我引用這只是失敗從靜態庫中進行日誌記錄。如果我使用EXE項目中的相同(或類似)宏,它根本不會失敗。所以我似乎無法在某種單獨的測試應用程序中複製這個問題。

回答

0

該問題是由enum被解釋的方式引起的。編譯器調用模板<<運算符,而不是採用int類型的<<運算符的版本。什麼是更奇怪的(對我來說)是一個測試應用程序,我寫看到枚舉數據類型是否是問題的工作沒有問題,即:

ezx::net::client_state::state mystate = ezx::net::client_state::connecting; 
LOG_INFO("this should show new state" << mystate); 

這並沒有拋出任何錯誤,並採取不同的代碼路徑比上面的代碼相同。

我得出的結論是,這個操作符的log4cxx實現是脆弱的,因爲它可以很好地編譯,但在運行時會意外失敗,這取決於數據類型是否調度到正確的操作符版本。