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

2024-01-10

我有以下 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”从随机访问的 .dat 文件插入新用户/查看用户

//File.h
#ifndef FILE_H
#define FILE_H
#include "User.h"

class File{
    public:

             void loadUser(); 
             bool addUser(User&); 

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

我在运行时遇到上述问题。不过没有编译问题。

在处理内部具有“字符串属性”的对象时,是否存在任何问题?

请帮忙


我认为问题在于你将 C++ 代码与 C 思维方式混合在一起。 你真正应该在这里做的是使用提取运算符,opeartor>>(),以及 C++ IO 流。这与使用 C 标准 IO 和read()功能。要写入对象,请使用插入运算符operator<<()而不是Cwrite()功能。

对于使用字符串使用std::string。该类提供operator<<() and operator>>()。所以,你可以说std::string s进而io << s and io >> s where io是一些 C++ IO 流对象。这将做正确的事(tm)。这里的哲学是std::string类比你(用户)更了解如何序列化std::string目的。因此,让它使用 > 运算符来完成它。

继续这个想法,作为作者的你User,比任何人都更了解如何序列化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

从这里开始,将用户保存到您所说的文件中

std::ofstream f("filename");
User u("John");
f << u;

就是这样。读取用户:

std::ifstream f2("filename");
f2 >> u;

将代码包装在命名空间中是一个很好的做法。 IDE 通过自动完成功能显示有多少符号可见,从而很好地可视化了这个问题。你会看到全球范围内有多么混乱。通过将代码包装在命名空间中,您可以将其分组到范围名称下,从而在全局名称范围中节省更多混乱。这只是为了保持整洁。如果您将代码放在您自己的命名空间中,那么您可以为函数、类或变量选择任何您想要的名称,只要您之前没有选择过即可。如果您不将其放在命名空间中,那么您需要与其他人共享名称。这就像一只臭鼬宣布自己的领地,只是没有床味。

关于这一点,我建议你把它拿掉using namespace std从你的标题中。这将带来所有符号std命名空间进入所有文件的范围#include标题。这是一个不好的做法。只说using namespace std如果您愿意,可以在实现文件中,但不在头文件中。

当然,有些人会说这也是一个坏主意。我个人认为,如果您意识到该特定实现文件中可能存在名称冲突这一事实,那就很好。但至少你知道那在哪里using声明是:它位于您的实现文件中,并且只会导致该实现文件中的冲突。它有点像一把枪(一把塑料水枪,但仍然是一把枪),只是你只能射(湿)自己的脚,而不能射别人的脚。我认为这完全没问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从随机访问文件读取对象时 C++ 程序崩溃 的相关文章

随机推荐