C ++访问冲突错误

时间:2015-11-08 08:19:42

标签: c++ random-access

我写了一个简单的程序来学习如何使用随机访问填充。它可以很好地编译,但在运行时会出现访问冲突错误。我只是在写和读一条记录。

标题文件:

#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();
}

读取功能后发生错误。在read函数结束时cout“Read Successful”运行正常,之后在main中没有其他语句。我不知道造成错误的原因。

1 个答案:

答案 0 :(得分:1)

代码中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会调用未定义的行为,这不应该让您感到惊讶。

在C ++ [*] 中,非POD类型的序列化和特别是反序列化并不容易,并且尚未标准化。您可以考虑使用第三方库。与往常一样,Boost在第三方库方面值得一试,事实证明,它确实包含一个序列化库,即Boost.Serialization

[*] 实际上,在任何语言中都不容易,甚至在那些假装容易使用的语言中也是如此,例如Java具有高度危险的Serializable接口。功能