提问人:urbanite 提问时间:7/15/2015 最后编辑:urbanite 更新时间:7/16/2015 访问量:156
在 IDE 外部运行时的 std::ifstream 问题
std::ifstream issue when running outside of IDE
问:
我有一个函数,在 Visual Studio 调试环境(同时具有 Debug 和 Release 配置)中运行时工作正常,但是在 IDE 外部运行应用程序时,就像最终用户一样,程序会崩溃。这发生在调试和发布版本中。
我知道调试和发布配置(优化、调试符号等)之间可能存在的差异,并且至少在一定程度上了解在 Visual Studio 内部运行应用程序与在 Visual Studio 外部运行应用程序之间的差异(调试堆、工作目录等)。我看过其中的几件事,但似乎没有一个能解决这个问题。这实际上是我第一次在 SO 上发帖;通常我可以从现有帖子中找到解决方案,所以我真的被难住了!
我能够附加调试器,奇怪的是,我收到两条不同的错误消息,具体取决于我是在 Windows 7 还是 Windows 8.1 上运行应用程序。对于 Windows 7,该错误只是访问冲突,它会在 return 语句中中断。对于 Windows 8.1,这是一个堆损坏错误,它会在 std::ifstream 的构造中中断。在这两种情况下,所有局部变量都正确填充,因此我知道这不是函数无法找到文件或将其内容读入缓冲区数据的问题。
同样有趣的是,这个问题在 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 获取文件大小,而不是执行搜索
更好的是,使用 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;
}
评论
std::vector<unit8_t> LoadFile(const char* filename)