繁体   English   中英

C++ 访问冲突错误

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM