简体   繁体   English

C++ 访问冲突错误

[英]C++ Access Violation Error

I wrote a simple program to learn how to use random access filling.我写了一个简单的程序来学习如何使用随机访问填充。 It compliles fine but on runtime gives the access violation error.它编译得很好,但在运行时给出了访问冲突错误。 I am only writing and reading a single record.我只写和读一个记录。

Header file:头文件:

#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

Implementation file:实现文件:

#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";
}

Main:主要的:

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

The error occurs after the read function.错误发生在读取函数之后。 The cout "Read Successful" at the end of the read function runs fine and there is no other statement after that in the main.读取函数末尾的 cout“读取成功”运行良好,之后在 main 中没有其他语句。 I dont know what is causing the error.我不知道是什么导致了错误。

Every occurence of reinterpret_cast in your code should give you a strong hint that something dangerous and error-prone is happening. 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"; }

This cannot work correctly.这不能正常工作。 All language-lawyer issues aside, consider the implementation point of view here.撇开所有语言律师问题不谈,请考虑此处的实施观点。 A std::string normally does not directly contain (as a data member) the text it represents, but instead contains a pointer to dynamically allocated memory where the text is stored. std::string通常不直接包含(作为数据成员)它表示的文本,而是包含一个指向动态分配的存储文本的内存的指针

So what you do end up doing here is writing a memory address into the file.因此,您最终要做的是将内存地址写入文件。

This is already sufficient for the approach to be doomed for any serialisation business, because obviously, memory addresses are different for different runs of the same program.对于任何序列化业务来说,这已经足以让该方法注定失败,因为显然,同一程序不同运行的内存地址是不同的。

But it won't work even in this simple example when the file is written to and read from within the same execution.但即使在这个简单的例子中,当文件在同一个执行中写入和读取时,它也不起作用。 a is a local object. a是本地对象。 When write finishes, the object is destroyed, and with it the std::string it contains.write完成时,对象被销毁,并且包含它的std::string When a std::string is destroyed, the memory it had allocated for its contents is released.std::string被销毁时,它为其内容分配的内存被释放。

Consequently, as soon as write is done, your file contains an invalid memory address.因此,一旦write完成,您的文件就会包含无效的内存地址。 A few moments later, in the read function, you try to stuff that invalid address into a new std::string .片刻之后,在read函数中,您尝试将该无效地址填充到新的std::string Luckily enough, you get an access violation so that you notice something is wrong.幸运的是,您遇到了访问冲突,因此您会发现有问题。 If you were unlucky, the program would have continued to produce the desired behaviour for a while, only to start crashing or doing strange things at a later point.如果你不走运,程序会在一段时间内继续产生所需的行为,只是在稍后开始崩溃或做一些奇怪的事情。


Some issues which make the situation even more complicated:一些使情况更加复杂的问题:

  • The memory layout of std::string is unspecified by the C++ standard. C++ 标准未指定std::string的内存布局。 Different compilers with different compiler settings will thus produce different info.dat files even when you have compiled them from exactly the same C++ source code.因此,具有不同编译器设置的不同编译器将生成不同的info.dat文件,即使您是从完全相同的 C++ 源代码编译它们。

  • std::string may or may not use Small-String Optimisation (SSO), a technique which means that for strings with only a few characters, the text is directly stored in the object instead of being dynamically allocated. std::string可以或可以不使用小字符串优化(SSO),这意味着,对于具有仅几个字符的字符串,文本直接存储在对象,而不是被动态分配的技术。 So you cannot even assume the presence of a pointer.所以你甚至不能假设一个指针的存在。

  • On the other hand, std::string may contain even more pointers to dynamically allocated memory, pointing to the end of the represented text and to the end of the allocated memory (for the capacity member function).另一方面, std::string可能包含更多指向动态分配内存的指针,指向所表示文本的结尾和分配内存的结尾(对于capacity成员函数)。


Considering all of those important internal complexities, it should not surprise you that your attempt at bypassing or ignoring all of them with a simple reinterpret_cast invokes undefined behaviour .考虑到所有这些重要的内部复杂性,您通过简单的reinterpret_cast绕过或忽略所有这些的尝试会调用未定义的行为,这一点应该不会让您感到惊讶。

Serialisation and especially deserialisation of non-POD types is not easy in C++ [*] and has not yet been standardised.序列化,尤其是非 POD 类型的反序列化在 C++ [*] 中并不容易,并且尚未标准化。 You may consider a third-party library.您可以考虑使用第三方库。 As always, Boost is worth a try when it comes to third-party libraries, and as it turns out, it does contain a serialisation library, namely Boost.Serialization .与往常一样,Boost 在第三方库方面值得一试,而且事实证明,它确实包含一个序列化库,即Boost.Serialization


[*] Actually, it's not easy in any language, not even in those which pretend to make it easy, such as Java with its highly dangerous Serializable interface. [*]实际上,这在任何语言中都不容易,即使在那些假装很容易的语言中也是如此,例如具有高度危险的Serializable接口的 Java。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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