是什么导致fstream::open在这里失败?



问题

我正在Win32 c++中开发一个简单的记事本应用程序。然而,我遇到了一个问题,打开一个文件保存到。有相当多的代码(你可以在这里找到),但导致错误的行是在文件Event Handlers.cpp.

特别是第25行

wnd.file.open(wnd.filePath, std::ios_base::out);

抛出异常。下面是调试输出:

Exception thrown: read access violation.
this->**_Ptr** was nullptr.

虽然_Ptr并不总是nullptr的值。


What I've try

这就是问题的要点。以下是我到目前为止所做的尝试。

  • 检查另存为对话框的结果(wnd.filePath的值)-它确实是正确的文件路径字符串
  • 在打开文件流之前刷新、清除、关闭文件流
  • 改变打开模式
  • 我想也许fstream对象不能是全局的,因为我注意到std::filebuf成员对于全局流总是NULL,而不是本地流。这其实不是问题。
  • 和过去几天的许多其他事情,不幸的是我不记得了

我的理论然而,我认为问题出在我的代码和std::fstream类的设计上。

Main.cpp第34行:

mainWnd = TopLevelWnd(wr.left, wr.right, wr.left, wr.top, 1280, 720, wr.right - wr.left,
wr.bottom - wr.top, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
0, L"Main Window Class", L"Main Window", hInstance);

构造一个TopLevelWnd,然后复制到全局向量windows中默认构造的TopLevelWnd。据我所知,类std::fstream的复制成员已被删除,无法复制。这应该会产生编译错误,因为它是TopLevelWnd的成员,但它没有。无论如何,我决定删除TopLevelWnd的复制成员,并编写move构造函数和move赋值操作符函数,并使用std::move显式调用它们:

// delete copy members because fstream cannot be copied
TopLevelWnd& operator=(const TopLevelWnd&) = delete;
TopLevelWnd(const TopLevelWnd&) = delete;

// move members
TopLevelWnd(TopLevelWnd&& source)
: Wnd(std::move(source)),
file(std::move(source.file))
{}
TopLevelWnd& operator=(TopLevelWnd&& right)
{
Wnd::operator=(std::move(right));
file = std::move(right.file);
return *this;
}

这也不能解决问题,所以我完全不知所措。有人能帮我理解吗?

注:顺便说一下,要重现这个问题,您只需运行程序并在菜单中单击File->Save并选择要保存到的文件。

经过大量的挖掘和实验,我终于找到了答案。问题出在TopLevelWnd构造函数中。

TopLevelWnd(int x, int y, int ncX, int ncY, int width, int height, int ncWidth, int ncHeight, DWORD styles, DWORD exStyles, const wchar_t* className, const wchar_t* name, HINSTANCE hInstance = GetModuleHandleW(nullptr), HWND hWnd = nullptr, HWND hWndParent = nullptr, HMENU hMenu = nullptr)
: Wnd(x, y, ncX, ncY, width, height, ncWidth, ncHeight, styles, exStyles, className, name, hInstance ,hWnd, hWndParent),
hMenu(hMenu)

接受两个参数hWndhMenu。该类还有两个数据成员hWndhMenu。在正文中,我写了这样的行:

hWnd = CreateWindowExW(...);
hMenu = CreateMenu();

当我需要写

this->hWnd = CreateWindowExW(...)
this->hMenu = CreateMenu();

最新更新