Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/drupal/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;从随机访问文件读取对象时程序崩溃_C++_File Handling - Fatal编程技术网

C++ C++;从随机访问文件读取对象时程序崩溃

C++ C++;从随机访问文件读取对象时程序崩溃,c++,file-handling,C++,File Handling,我有下面的User.h,它包含几个属性(字符串)。User.cpp具有所有定义 //User.h #ifndef USER_H #define USER_H #include<iostream> #include <cstring> using namespace std; class User{ string username; public: User(); string getUsername() const;

我有下面的User.h,它包含几个属性(字符串)。User.cpp具有所有定义

//User.h
#ifndef USER_H
#define USER_H
#include<iostream>
#include <cstring>

using namespace std;

class User{

  string username;

  public:
         User();
         string getUsername() const;                      
         void setUsername(string);

};
#endif
文件类定义

//File.cpp
#include<cstring>
#include<iostream>
#include<iomanip>
#include<fstream>

#include "User.h"
#include "File.h"

using namespace std;

User tempUser;
fstream usersFile;

void File::loadUser(){
     usersFile.open("users.dat", ios::in | ios::binary);

     usersFile.seekg(0);  

     // commenting the following lines prevented the issue
     usersFile.read(reinterpret_cast<char *>(&tempUser), sizeof(tempUser)); 

     cout<<tempUser.getUsername().c_str(); 

     usersFile.close();
}

bool File::addUser(User& user){

     usersFile.open("users.dat", ios::out | ios::ate | ios::binary);

     // no issue when writing to file
     usersFile.write( reinterpret_cast<const char *>(&user), sizeof(user));

     usersFile.close();

     cout<<"User added";  
}
//File.cpp
#包括
#包括
#包括
#包括
#包括“User.h”
#包括“File.h”
使用名称空间std;
用户临时用户;
fstream用户文件;
void文件::loadUser(){
usersFile.open(“users.dat”,ios::in | ios::binary);
usersFile.seekg(0);
//对以下几行的评论阻止了这一问题
read(reinterpret_cast(&tempUser),sizeof(tempUser));

cout是的,std::string类不是简单的旧数据,换句话说,它包含指针。 如果以这种方式保存/加载string类,则不会加载/保存指向的数据,只加载/保存指针的值

此外,sizeof(tempUser)不包括字符串指向的文本大小

您的解决方案是更改读取/写入数据的方式。 一种方法是使用boost::serialization,它处理诸如std::string之类的数据类型。
另一种方法是自己将每个字符串写入文本文档中的单独一行(不是二进制模式),然后使用readline将其读回。

字符串是一个对象,这意味着您没有写入它的内容


尝试编写一个用户并检查该文件,以了解我的意思。然后,您将读取一些指向无效内存位置的指针。

与其构建自己的自定义序列化代码,不如做一些您想做的事情,而不费吹灰之力。它非常适合将简单的结构化数据从一个地方传递到另一个地方。

你不能像那样读取非POD类型。字符串不是POD类型。

根据字符串的存储方式,有几种方法可以正确读取字符串

对于文本文件:

如果字符串只是一个单词,两边用空格分隔,则可以使用普通的旧>>运算符。如果它是多个单词,则可以将其存储在自己的行中,并使用getline

对于二进制文件:


将字符串以空终止形式存储。一次读取一个字符,检查空字符。或者,用一个整数来存储字符串的大小。当你读它时,首先读入整数,然后读很多字符。

< P>我认为问题是你将C++代码和C心态混合在一起。 在这里,你真正要做的是使用提取算子,<代码> opror >()>代码>,同时使用C++ IO流。这与使用C标准IO一起使用<代码>读()(代码)>函数。 继续这个想法,作为
User
的作者,您比任何人都更了解如何序列化
User
对象。因此,为类用户提供>操作符作为一项服务。“类用户”一周后,您可能完全忘记了如何正确序列化
用户
对象。(或者,您认为自己还记得,但实际上忘记了一个细节,导致代码中出现错误)。示例:

// in User.h
#include <string>
#include <iosfwd>  // forward declarations of standard IO streams

namespace mine {
class User {
    User(const std::string& name) : username(name) { }
    friend std::ostream& operator<<(std::ostream&, const User&);
    friend std::istream& operator>>(std::istream&, User&);

private:
    std::string username;
};

std::ostream& operator<<(std::ostream& out, const User& u)
{
    return out << u.username;
}

std::istream& operator>>(std::istream& in, User& u)
{
    return in >> u.username;
}
}  // namespace mine
将代码包装在命名空间中是一种很好的做法。IDE通过显示自动完成功能可以看到多少符号,从而很好地可视化了这个问题。您可以看到全局作用域中有多少混乱。通过将代码包装在命名空间中,您可以将其分组到作用域名称下,从而在全局范围中节省更多混乱e scope。这只是为了保持整洁。如果你将代码放在自己的命名空间中,那么你可以为函数、类或变量选择任何你想要的名称,只要你以前没有选择过。如果你不将其放在命名空间中,那么你需要与其他人共享名称。这就像臭鼬声明自己的领地,只是没有臭味。

在这一点上,我建议您将
使用名称空间std
从头文件中删除。这会将
std
名称空间中的所有符号纳入所有
#包括
头文件的范围。这是一种不好的做法。如果愿意,只在实现文件中说
使用名称空间std
,而不在头文件中说

当然,有些人甚至会说这是一个坏主意。我个人认为,如果您意识到在特定的实现文件中可能存在名称冲突的事实,那就好了。但至少您知道使用
语句的
在哪里:它在您的实现文件中,并且只会在该实现文件中引起冲突。这是一种错误n、 (一把塑料水枪,但仍然是一把枪),只有你才能射(湿)自己的脚,而不是别人的脚。在我看来,这是非常好的

// in User.h
#include <string>
#include <iosfwd>  // forward declarations of standard IO streams

namespace mine {
class User {
    User(const std::string& name) : username(name) { }
    friend std::ostream& operator<<(std::ostream&, const User&);
    friend std::istream& operator>>(std::istream&, User&);

private:
    std::string username;
};

std::ostream& operator<<(std::ostream& out, const User& u)
{
    return out << u.username;
}

std::istream& operator>>(std::istream& in, User& u)
{
    return in >> u.username;
}
}  // namespace mine
std::ofstream f("filename");
User u("John");
f << u;
std::ifstream f2("filename");
f2 >> u;