[英]C++ Access Violation Error
我写了一个简单的程序来学习如何使用随机访问填充。 它编译得很好,但在运行时给出了访问冲突错误。 我只写和读一个记录。
头文件:
#include<iostream>
#include<string>
#include<fstream>
using namespace std;
#ifndef HEADER_H
#define HEADER_H
class info
{
private:
int id;
string name;
public:
info(int = 0, string = " ");
void set(int, string);
void display();
void write();
void read();
};
#endif
实现文件:
#include<iostream>
#include<string>
#include<fstream>
#include"Header.h"
using namespace std;
info::info(int x, string y)
{
set(x, y);
}
void info::set(int x, string y)
{
id = x;
name = y;
}
void info::display()
{
cout << "\n\n\tid : " << id;
cout << "\n\tname" << name;
}
void info::write()
{
ofstream o("info.dat", ios::out | ios::binary | ios::app);
info a(id, name);
info *p = &a;
o.write(reinterpret_cast<const char *>(p), sizeof(info));
o.close();
cout << "\n\n\tWrite Successful";
}
void info::read()
{
ifstream i("info.dat", ios::in | ios::binary);
i.seekg(0);
info a(0, "a");
info *p = &a;
i.read(reinterpret_cast<char *>(p), sizeof(info));
i.close();
p->display();
cout << "\n\n\tRead Successful";
}
主要的:
#include<iostream>
#include<string>
#include<fstream>
#include"Header.h"
using namespace std;
void main()
{
info a(10, "muaaz");
a.write();
a.display();
info b(2, "m");
b.read();
}
错误发生在读取函数之后。 读取函数末尾的 cout“读取成功”运行良好,之后在 main 中没有其他语句。 我不知道是什么导致了错误。
reinterpret_cast
在你的代码中的每一次出现都应该给你一个强烈的暗示,表明正在发生一些危险且容易出错的事情。
void info::write() { ofstream o("info.dat", ios::out | ios::binary | ios::app); info a(id, name); info *p = &a; o.write(reinterpret_cast<const char *>(p), sizeof(info)); o.close(); cout << "\\n\\n\\tWrite Successful"; }
这不能正常工作。 撇开所有语言律师问题不谈,请考虑此处的实施观点。 std::string
通常不直接包含(作为数据成员)它表示的文本,而是包含一个指向动态分配的存储文本的内存的指针。
因此,您最终要做的是将内存地址写入文件。
对于任何序列化业务来说,这已经足以让该方法注定失败,因为显然,同一程序不同运行的内存地址是不同的。
但即使在这个简单的例子中,当文件在同一个执行中写入和读取时,它也不起作用。 a
是本地对象。 当write
完成时,对象被销毁,并且包含它的std::string
。 当std::string
被销毁时,它为其内容分配的内存被释放。
因此,一旦write
完成,您的文件就会包含无效的内存地址。 片刻之后,在read
函数中,您尝试将该无效地址填充到新的std::string
。 幸运的是,您遇到了访问冲突,因此您会发现有问题。 如果你不走运,程序会在一段时间内继续产生所需的行为,只是在稍后开始崩溃或做一些奇怪的事情。
一些使情况更加复杂的问题:
C++ 标准未指定std::string
的内存布局。 因此,具有不同编译器设置的不同编译器将生成不同的info.dat
文件,即使您是从完全相同的 C++ 源代码编译它们。
std::string
可以或可以不使用小字符串优化(SSO),这意味着,对于具有仅几个字符的字符串,文本被直接存储在对象,而不是被动态分配的技术。 所以你甚至不能假设一个指针的存在。
另一方面, std::string
可能包含更多指向动态分配内存的指针,指向所表示文本的结尾和分配内存的结尾(对于capacity
成员函数)。
考虑到所有这些重要的内部复杂性,您通过简单的reinterpret_cast
绕过或忽略所有这些的尝试会调用未定义的行为,这一点应该不会让您感到惊讶。
序列化,尤其是非 POD 类型的反序列化在 C++ [*] 中并不容易,并且尚未标准化。 您可以考虑使用第三方库。 与往常一样,Boost 在第三方库方面值得一试,而且事实证明,它确实包含一个序列化库,即Boost.Serialization 。
[*]实际上,这在任何语言中都不容易,即使在那些假装很容易的语言中也是如此,例如具有高度危险的Serializable
接口的 Java。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.