0

错误消息是:“0x7c810eac”处的指令引用了“0x00000000”处的内存。内存无法“写入”。

如果我删除析构函数一切都很好。但我不明白这里发生了什么。我在任何地方都读到我应该关闭句柄,但这里的代码不允许我这样做。(是的,我知道我可以手动完成......但这是客户端代码中不必要的行,我认为应该由对象处理。)

#include <windows.h>
#include <iostream>
#include <string>

struct fileHandle {
  HANDLE hFile;
  fileHandle(std::string path) {
    hFile = CreateFile(path.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_ARCHIVE, NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
      printf("error: INVALID_HANDLE_VALUE");
    }
  }
  ~fileHandle() {
    CloseHandle(hFile);
  }
  void save(std::string data) {
    if (!WriteFile(hFile, data.c_str(), data.size(), NULL, NULL)) {
      printf("WriteFile failed: ", GetLastError());
    }
  }
};

int main() {
  fileHandle my_handle("test_file.txt");
  my_handle.save("some text");
}

更新:当文件不存在时会发生这种情况。当文件确实存在程序打印错误时,但这是有意的。我在这里要求仅在创建文件时覆盖这种情况(我知道如何重写句柄创建以覆盖现有文件。)

编译器:http: //sourceforge.net/projects/mingwbuilds/files/host-windows/releases/4.7.2/32-bit/threads-posix/sjlj/x32-4.7.2-release-posix-sjlj-rev7。 7z

更新 2:我没有提到此代码有效并写入文件。最后触发内存错误。

4

7 回答 7

3

请使用 -Wall 编译所有代码。节省大量时间。

在您的代码printf中具有无效的格式字符串。正确的解决方案printf是(注意%lu):

void save(std::string data) {
  if (!WriteFile(hFile, data.c_str(), data.size(), NULL, NULL)) {
    printf("WriteFile failed: %lu", GetLastError());
  }
}

如果您使用 编译-Wall,您的代码会给出警告:

filehandle.cpp: In member function 'void fileHandle::save(std::string)':
filehandle.cpp:18:50: warning: too many arguments for format [-Wformat-extra-args]

此外,您应该打印错误,stderr因为它是无缓冲的。printf使用缓冲区,这就是为什么你没有得到任何输出。\n在错误之后添加一个也是一个好主意。

另请阅读其他答案以改进您的代码。使用三法则


阅读评论后,我意识到这确实不是段错误的原因。(另请查看 Ron Burk 的解决方案,看看出了什么问题。)

根据 Windows API 文档,lpNumberOfBytesWritten参数NULL只能在lpOverlapped parameteris not时使用NULL

所以你必须给一个指向一个 DWORD 的指针,WriteFile 可以在其中存储它实际读取的字节数。最后的保存将是:

void save(std::string data) {
  DWORD writtenBytes;
  if (!WriteFile(hFile, data.c_str(), data.size(), &writtenBytes, NULL)) {
    printf("WriteFile failed: %lu", GetLastError());
  }
}

如果文件存在,则不会弹出错误,因为将 INVALID_HANDLE_VALUE 传递给 WriteFile 似乎使 WriteFile 在使用您的指针之前返回。

于 2013-02-10T22:29:58.433 回答
3

WriteFile() 的参数错误。倒数第二个参数不能为 NULL。将其更改为您设置为 0 的 DWORD 的地址,一切都会正常工作。当它试图写回写入的字节数时,它在内核中的 WriteFile() 中死亡。

于 2013-02-10T23:18:34.270 回答
3

CloseHandle 的文档清楚地说明了为什么会发生这种情况:

如果应用程序在调试器下运行,则如果函数接收到无效的句柄值或伪句柄值,则该函数将引发异常。

因此,当您对 CreateFile 的调用失败时,对 CloseHandle 的后续调用将引发 SEH 异常。

解决方案是,如果对 CreateFile 的调用成功,您的代码必须仅调用 CloseHandle。

正如其他人指出的那样,您对 WriteFile 的使用是错误的。我不会在这里重复细节。

于 2013-02-11T07:43:04.793 回答
0
~fileHandle() {
    if(hFile != INVALID_HANDLE_VALUE)
        CloseHandle(hFile);
  }
于 2013-02-10T22:14:12.257 回答
0

您没有遵循三原则-因此,由于编译器生成的复制构造函数和复制赋值运算符的浅层,所有权hFile在副本之间共享。fileHandle

例如:

fileHandle my_handle("test_file.txt");
fileHandle my_second_handle = my_handle;

其中哪一个实际上应该关闭销毁句柄?首先?当第二个超出范围并调用析构函数时会发生什么?

在这种情况下,我会说您应该禁止复制或分配,或查明所有权。

编辑:在您的片段中,问题可能是 Ron 指出的问题,但这仍然是重要的一点。

不过,我不会这样对待它。我认为如果文件无法打开,fileHandle就不应该存在。拥有无效对象有什么意义?我只是在构造函数中抛出一个异常以禁止无效对象,而不是在析构函数中进行检查。

fileHandle(std::string path) {
    hFile = CreateFile(path.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_ARCHIVE, NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
       throw std::exception("file not found");
    }
  }
于 2013-02-10T22:14:28.520 回答
0

您需要检查文件是否已正确打开。

 if (hFile != INVALID_HANDLE_VALUE) CloseFile(hFile);
于 2013-02-10T22:14:31.613 回答
0

为了安全起见,请使用

~fileHandle() 
{

            if (hfile != INVALID_HANDLE_VALUE)
            {
                CloseHandle(hfile);
                hfile = INVALID_HANDLE_VALUE;
            }
}
于 2021-09-13T17:49:21.760 回答