在IDE外运行时出现std::ifstream问题

std::ifstream issue when running outside of IDE

本文关键字:std ifstream 问题 IDE 运行时      更新时间:2023-10-16

我有一个在Visual Studio调试环境中运行时工作良好的函数(带有调试和发布配置),但是当在IDE的外部运行应用程序时,就像最终用户会做的那样,程序崩溃了。这在Debug和Release版本中都会发生。

我知道调试和发布配置(优化,调试符号等)之间可能存在的差异,至少在某种程度上知道在Visual Studio内部运行应用程序与在它外部运行应用程序(调试堆,工作目录等)之间的差异。我看过其中的一些东西,但似乎没有一个能解决这个问题。这实际上是我第一次张贴到SO;通常我可以从现有的帖子中找到解决方案,所以我真的被难住了!

我能够附加一个调试器,奇怪的是,我得到两个不同的错误信息,基于我是否在Windows 7和Windows 8.1上运行应用程序。对于Windows 7,这个错误只是一个访问冲突,它在返回语句时就中断了。对于Windows 8.1,这是一个堆损坏错误,它在std::ifstream的构造上中断。在这两种情况下,所有的局部变量都被正确填充,所以我知道这不是函数无法找到文件或将其内容读入缓冲区data的问题。

同样有趣的是,这个问题在Windows 8.1上发生的几率只有20%,在Windows 7上发生的几率是100%,尽管这可能与这两个操作系统运行在不同的硬件上有关。

我不确定它有什么区别,但项目类型是Win32桌面应用程序,它初始化DirectX 11。你会注意到文件类型被解释为二进制,这是正确的,因为这个函数主要是加载编译过的着色器。

静态成员函数LoadFile:

HRESULT MyClass::LoadFile(_In_ const CHAR* filename, _Out_ BYTE** data, _Out_ SIZE_T* length)
{
    CHAR pwd[MAX_PATH];
    GetCurrentDirectoryA(MAX_PATH, pwd);
    std::string fullFilePath = std::string(pwd) + "\" + filename;
    std::ifstream file(fullFilePath, std::ifstream::binary);
    if (file)
    {
        file.seekg(0, file.end);
        *length = (SIZE_T)file.tellg();
        file.seekg(0, file.beg);
        *data = new BYTE[*length];
        file.read(reinterpret_cast<CHAR*>(*data), *length);
        if (file) return S_OK;
    }
    return E_FAIL;
}

更新:

有趣的是,如果我在堆上分配std::ifstream 文件而不删除它,问题就会消失。在我的例子中,一定是ifstream的销毁引起了问题。
  • 你不检查GetCurrentDirectoryA的返回值-也许你的当前目录名称太长或什么?

  • 如果您已经使用Win32(不可移植!),使用GetFileSize来获取文件大小,而不是执行seek

  • 更好的是,使用boost来编写可移植代码

  • 打开编译器选项中的所有警告

  • 启用ios异常

好吧,我放弃了尝试使用ifstream。显然,我不是唯一一个有这个问题的人……搜索"ifstream destructor crash"

因为这个应用程序是基于DirectX的,只会在Windows上运行,我去了Windows API路线,一切都工作得很好。

工作代码,以防有人关心:

HRESULT MyClass::LoadFile(_In_ const CHAR* filename, _Out_ BYTE** data, _Out_ SIZE_T* length)
{
    CHAR pwd[MAX_PATH];
    GetCurrentDirectoryA(MAX_PATH, pwd);
    string fullFilePath = string(pwd) + "\" + filename;
    WIN32_FIND_DATAA fileData;
    HANDLE file = FindFirstFileA(fullFilePath.c_str(), &fileData);
    if (file == INVALID_HANDLE_VALUE) return E_FAIL;
    file = CreateFileA(fullFilePath.c_str(),
        GENERIC_READ,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL);
    if (file == INVALID_HANDLE_VALUE) return E_FAIL;
    *length = (SIZE_T)fileData.nFileSizeLow;
    *data = new BYTE[*length];
    DWORD bytesRead;
    if (ReadFile(file, *data, *length, &bytesRead, NULL) == FALSE || bytesRead != *length)
    {
        delete[] *data;
        *length = 0;
        CloseHandle(file);
        return E_FAIL;
    }
    CloseHandle(file);
    return S_OK;
}