std::ifstream 当 运行 在 IDE 之外时出现问题
std::ifstream issue when running outside of IDE
我有一个函数在 运行 在 Visual Studio 调试环境(具有调试和发布配置)中时工作正常,但是当 运行 应用程序 在 IDE 之外 ,就像最终用户会做的那样,程序崩溃了。 Debug 和 Release 版本都会发生这种情况。
我知道调试和发布配置之间可能存在的差异(优化、调试符号等),并且至少在一定程度上了解运行 Visual Studio 中的应用程序之间的差异] 与外部(调试堆、工作目录等)。我已经查看了其中的一些内容,none 似乎解决了这个问题。这实际上是我第一次发布到 SO;通常我可以从现有帖子中找到解决方案,所以我真的很困惑!
我能够附加一个调试器,奇怪的是我收到两条不同的错误消息,这取决于我是 运行 Windows 7 还是 Windows 8.1 上的应用程序。对于 Windows 7,错误只是一个访问冲突,它在 return 语句上中断。对于 Windows 8.1,这是一个堆损坏错误,它在 std::ifstream 的构造中中断。在这两种情况下,所有局部变量都被正确填充,所以我知道这不是函数无法找到文件或无法将其内容读入缓冲区 data 的问题。
同样有趣的是,这个问题在 Windows 8.1 上只有大约 20% 的时间发生,而在 Windows 7 上有 100% 的时间发生,尽管这可能与截然不同的这些OS的硬件是运行。
我不确定它有什么不同,但项目类型是 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 file 并且不删除它,问题就会消失。在我的案例中,一定有一些关于 ifstream 的破坏导致了问题。
您没有检查 GetCurrentDirectoryA 的 return 值 - 也许您当前的目录名称太长或其他原因?
如果您已经在使用 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;
}
我有一个函数在 运行 在 Visual Studio 调试环境(具有调试和发布配置)中时工作正常,但是当 运行 应用程序 在 IDE 之外 ,就像最终用户会做的那样,程序崩溃了。 Debug 和 Release 版本都会发生这种情况。
我知道调试和发布配置之间可能存在的差异(优化、调试符号等),并且至少在一定程度上了解运行 Visual Studio 中的应用程序之间的差异] 与外部(调试堆、工作目录等)。我已经查看了其中的一些内容,none 似乎解决了这个问题。这实际上是我第一次发布到 SO;通常我可以从现有帖子中找到解决方案,所以我真的很困惑!
我能够附加一个调试器,奇怪的是我收到两条不同的错误消息,这取决于我是 运行 Windows 7 还是 Windows 8.1 上的应用程序。对于 Windows 7,错误只是一个访问冲突,它在 return 语句上中断。对于 Windows 8.1,这是一个堆损坏错误,它在 std::ifstream 的构造中中断。在这两种情况下,所有局部变量都被正确填充,所以我知道这不是函数无法找到文件或无法将其内容读入缓冲区 data 的问题。
同样有趣的是,这个问题在 Windows 8.1 上只有大约 20% 的时间发生,而在 Windows 7 上有 100% 的时间发生,尽管这可能与截然不同的这些OS的硬件是运行。
我不确定它有什么不同,但项目类型是 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 file 并且不删除它,问题就会消失。在我的案例中,一定有一些关于 ifstream 的破坏导致了问题。
您没有检查 GetCurrentDirectoryA 的 return 值 - 也许您当前的目录名称太长或其他原因?
如果您已经在使用 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;
}