奇怪的std :: wcout行为

时间:2016-12-02 17:50:07

标签: c++ visual-studio

在编写简单的游戏引擎框架时,我遇到了一个奇怪的错误,使用std :: wcout在关闭和销毁对象期间记录消息。输出被截断,应用程序不会终止,但是不会抛出异常。我怀疑在消息完全显示之前,某些对象正在被销毁。

以下是应用程序通过“正常”关机序列时的输出。

Note truncated text

这是WinMain -

using namespace sge;

extern BaseApp *SGEApp;

LRESULT CALLBACK NullWinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    return DefWindowProc(hwnd, message, wParam, lParam);
}


int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR lpszCmdLine, int nCmdShow)
{
#if defined(_DEBUG) | !defined(NDEBUG)
    SGE_LEAK_CHECK;
    SGE_LEAK_CHECK_BREAK(0);
#endif

    /////////////////////

    // TODO: move this block of code to a console object
    if (!GetConsoleWindow()) {
        AllocConsole();
        FILE *pCout;
        FILE *pCerr;
        FILE *pCin;
        freopen_s(&pCout, "CONOUT$", "w", stdout);
        freopen_s(&pCerr, "CONOUT$", "w", stderr);
        freopen_s(&pCin,  "CONIN$",  "r", stdin);

        std::wcout.clear();
        std::wcerr.clear();
        std::wcin.clear();
        SetConsoleTitle(L"Framework Console");
        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED);
    }

    SetThreadAffinityMask(GetCurrentThread(), 1);

    bool bRun(true);
    MSG msg;

    if (!SGEApp->initialize())
        return -1;

    while (bRun) {
        while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
            TranslateMessage(&msg);
            DispatchMessageW(&msg);
        }
        if (GetAsyncKeyState(VK_PAUSE) || msg.message == WM_QUIT)
            bRun = false;

        SGEApp->update();
        SGEApp->draw();
    }
    delete SGEApp;

    FreeConsole();

    return int(0);
}

申请对象 -

#pragma once
#ifndef _APP_H
#define _APP_H

#ifndef SGE_BASEAPP_H
#include "Application/OpenglApp.h"
#endif

using namespace sge;

class app : public OpenglApp
{
public:
    app();
    ~app();

};

#include "App.h"
BaseApp *SGEApp = new app();

app::app()
{

}

app::~app()
{
}

#pragma once
#ifndef SGE_BASEAPP_H
#define SGE_BASEAPP_H


#ifndef SGE_LOGGER_H
#include "Core/Logger/Logger.h"
#endif



namespace sge
{


class BaseApp
{
public:
    BaseApp();
    virtual ~BaseApp();

    virtual bool initialize();
    virtual bool shutDown();
    virtual void update();
    virtual void draw();

    virtual Logger *getLogger() const { return app_logger; }

protected:
    Logger *app_logger;
};

} // namespace sge

#endif // !SGE_BASEAPP_H

#include "BaseApp.h"

namespace sge
{

BaseApp::BaseApp()
{

}

BaseApp::~BaseApp()
{

}

bool BaseApp::initialize()
{
    return bool(false);
}

bool BaseApp::shutDown()
{
    return bool(false);
}

void BaseApp::update()
{

}

void BaseApp::draw()
{

}


} // namespace sge

#pragma once
#ifndef SGE_OPENGLAPP_H
#define SGE_OPENGLAPP_H

#ifndef SGE_BASEAPP_H
#include "BaseApp.h"
#endif

namespace sge
{

class OpenglApp : public BaseApp
{
public:
    OpenglApp();
    virtual ~OpenglApp();

    virtual bool initialize();
    virtual bool shutDown();
    virtual void update();
    virtual void draw();

};

} // namespace sge

#endif // SGE_OPENGLAPP_H

#include "Application/OpenglApp.h"

namespace sge
{

OpenglApp::OpenglApp()
{

}

OpenglApp::~OpenglApp()
{
    shutDown();
    app_logger->writeLogFile();
    delete app_logger;
}

bool OpenglApp::initialize()
{
    app_logger = new Logger();
    app_logger->log(SGEString(L"Begin initialization."), LOG_TRACE);

    app_logger->log(SGEString(L"Initialization succeeded."), LOG_TRACE);
    return bool(true);
}

bool OpenglApp::shutDown()
{
    SGEString msg();
    app_logger->log(SGEString(L"Begin shutdown."), LOG_TRACE);

    app_logger->log(SGEString(L"Shutdown succeeded."), LOG_TRACE);
    return bool(true);
}

void OpenglApp::update()
{

}

void OpenglApp::draw()
{

}


} // namespace sge

如果我在上面的shutDown()方法中注释两个log()调用,一切正常。

这是记录器类 -

#pragma once
#ifndef SGE_LOGGER_H
#define SGE_LOGGER_H


#ifndef _VECTOR_
#include <vector>
#endif
#ifndef _FSTREAM_
#include <fstream>
#endif


#ifndef SGE_TYPES_H
#include "Common/SGE_Types.h"
#endif

namespace sge
{

const SGEString DEFAULT_LOGFILE(L"Scavenger.log");

enum SGELogLevel : uint32 {
    LOG_ERROR = 0x0001,
    LOG_WARN  = 0x0002,
    LOG_INFO  = 0x0004,
    LOG_TRACE = 0x0008,
    LOG_DEBUG = 0x0010,
    LOG_CODE  = 0x0020,
};

struct SGELogData {
    SGELogData(uint32 severity, SGEString msg)
        : level(severity)
        , message(msg)
    {}
    uint32      level;
    SGEString   message;
};

class Logger
{
public:
    Logger();
    Logger(uint32 loglevel);
    ~Logger();

    bool initialize();
    bool shutdown();

    void log(SGEString message, uint32 level = LOG_ERROR);
    void log(uint32 level = 0xffff);

    void setLogFile(SGEString filespec, bool flush = false);
    bool writeLogFile(uint32 level = 0xffff);

protected:
    SGEString               logger_filespec;
    uint32                  logger_loglevel;
    std::vector<SGELogData> logger_logs;


};


} // namespace sge


#endif // !SGE_LOGGER_H

#include "Logger.h"


namespace sge
{

Logger::Logger()
    : logger_loglevel(0xffff)
    , logger_filespec(L"")
{

}

Logger::Logger(uint32 loglevel)
    : logger_loglevel(loglevel)
    , logger_filespec(L"")
{

}

Logger::~Logger()
{
    shutdown();
}

bool Logger::initialize()
{
    return bool(true);
}

bool Logger::shutdown()
{
    logger_logs.clear();
    return bool(true);
}

void Logger::log(SGEString message, uint32 level)
{
    SGEStringstream msg;
    SGEString       prefix;

    if (!logger_loglevel & level)
        return;

    prefix = L"";
    if(level & LOG_CODE)
        prefix = L"**CODE :";
    if(level & LOG_DEBUG)
        prefix = L"**DEBUG:";
    if(level & LOG_TRACE)
        prefix = L"**TRACE:";
    if(level & LOG_INFO)
        prefix = L"**INFO :";
    if(level & LOG_WARN)
        prefix = L"**WARN :";
    if(level & LOG_ERROR)
        prefix = L"**ERROR:";

    msg << prefix << L" " << message;
    logger_logs.push_back(SGELogData(level, message));
    std::wcout << msg.str().c_str() << std::endl;
}

void Logger::log(uint32 level)
{

    if (!logger_loglevel & level)
        return;
    for (auto i : logger_logs) {
        if (level & i.level) {
            uint32 l(level & i.level);
            SGEStringstream msg;
            SGEString       prefix;
            if (l & LOG_CODE)
                prefix = L"**CODE :";
            if (l & LOG_DEBUG)
                prefix = L"**DEBUG:";
            if (l & LOG_TRACE)
                prefix = L"**TRACE:";
            if (l & LOG_INFO)
                prefix = L"**INFO :";
            if (l & LOG_WARN)
                prefix = L"**WARN :";
            if (l & LOG_ERROR)
                prefix = L"**ERROR:";

            msg << prefix << L" " << i.message;
            std::wcout << msg.str() << std::endl;
        }
    }
}

void Logger::setLogFile(SGEString filespec, bool flush)
{
    if (flush)
        writeLogFile();
    logger_filespec = filespec;
}

bool Logger::writeLogFile(uint32 level)
{
    bool result(false);

    if (logger_filespec.empty())
        logger_filespec = DEFAULT_LOGFILE;

    std::wofstream file(logger_filespec, std::ios::in | std::ios::out | std::ios::trunc);
    if (!file) {
        log(SGEString(L"Unable to create log file!", LOG_ERROR));
        return result;
    }
    file << L"==================================================" << std::endl;
    file << L"Scavenger Log created:        " << __DATE__ << " " << __TIME__ << std::endl;
    file << L"Logger log level: 0x" << std::hex << logger_loglevel << " ";
    file << L"  File log level : 0x" << std::hex << level << std::endl;
    file << L"==================================================" << std::endl;
    for (auto i : logger_logs) {
        if (level & i.level) {
            uint32 l(level & i.level);
            //SGEStringstream msg;
            SGEString       prefix;
            if (l & LOG_CODE)
                prefix = L"**CODE :";
            if (l & LOG_DEBUG)
                prefix = L"**DEBUG:";
            if (l & LOG_TRACE)
                prefix = L"**TRACE:";
            if (l & LOG_INFO)
                prefix = L"**INFO :";
            if (l & LOG_WARN)
                prefix = L"**WARN :";
            if (l & LOG_ERROR)
                prefix = L"**ERROR:";

            file << prefix.c_str() << L" " << i.message.c_str() << std::endl;
        }
    }
    file.close();
    return bool(true);
}


} // namespace sge

我使用的某些已定义对象的片段 -

typedef std::wstring       SGEString;
typedef std::wstringstream SGEStringstream;
typedef std::wostream      SGECout;

我正在使用MSVC 2015社区版。当我单步执行关闭时,将显示所有消息并且应用程序正常退出。它只在正常运行时失败。任何帮助将不胜感激。

0 个答案:

没有答案