问题
我正在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)
接受两个参数hWnd
和hMenu
。该类还有两个数据成员hWnd
和hMenu
。在正文中,我写了这样的行:
hWnd = CreateWindowExW(...);
hMenu = CreateMenu();
当我需要写
时this->hWnd = CreateWindowExW(...)
this->hMenu = CreateMenu();