我尝试使用fstream
,虽然显然编译,程序崩溃。请告诉我上面的代码有什么问题,我应该怎么做才能纠正它
我想从二进制文件中恢复miperro5[]
的所有元素到一个新的数组miperro6[]
。怎样才能解决问题?
#include <stdio.h>
#include <iostream>
#include <Perro.hpp>
#include <fstream>
using std::cout;
using std::endl;
int main(int argc, char **argv)
{
Perro miperro5[5];
Perro miperro6[5];
miperro5[2].nombre = "lucky";
std::ofstream myfile;
myfile.open("example.bin", std::ios::out | std::ios::app | std::ios::binary);
for (int i = 0; i < 5; i++){
myfile.write(reinterpret_cast<char *>(&miperro5[i]), sizeof(Perro));
}
myfile.close();
std::ifstream myfile2;
myfile2.open("example.bin", std::ios::in | std::ios::binary);
for (int j = 0; j < 5; j++){
myfile2.read(reinterpret_cast<char *>(&miperro6[j]), sizeof(Perro));
}
myfile2.close();
for (int z = 0; z < 5; z++){
cout << miperro6[z].nombre << endl;
}
std::cin.get();
return 0;
}
这是Perro.hpp
#ifndef PERRO_HPP
#define PERRO_HPP
#include <string>
class Perro
{
public:
Perro();
~Perro();
void ladrar();
void comer();
std::string nombre;
int edad;
int arra[2];
};
#endif // PERRO_HPP
只能在类为POD类型时使用fwrite
和fread
。
Perro
不是POD类型,因为它有一个类型为std::string
的成员变量。
让我用一个简单的例子来说明这个问题。假设你有:
#include <iostream>
#include <fstream>
struct A
{
A(int s) : ip(new int[s]), size(s) {}
~A() { delete [] ip; }
int* ip;
int size;
};
int main()
{
A a1(10);
A a2(5);
std::cout << "a1.size: " << a1.size << ", a1.ip: " << a1.ip << std::endl;
std::ofstream myfile;
myfile.open("example.bin", std::ios::out | std::ios::binary);
myfile.write(reinterpret_cast<char *>(&a1), sizeof(A));
myfile.close();
std::ifstream myfile2;
myfile2.open("example.bin", std::ios::in | std::ios::binary);
myfile2.read(reinterpret_cast<char *>(&a2), sizeof(A));
myfile2.close();
std::cout << "a2.size: " << a2.size << ", a2.ip: " << a2.ip << std::endl;
return 0;
}
当我运行程序时,我得到以下输出:
<>之前a1。尺寸:10号,a1号。知识产权:0 x16b4010a2。尺寸:10,a2。知识产权:0 x16b4010***输入错误。/test-328': double free or corruption (fasttop): 0x00000000016b4010 ***流产之前这里发生的事情是a1.ip
的二进制值被写入文件,并将相同的二进制值读入a2.ip
。在读取之后,a1.ip
和a2.ip
都指向相同的内存位置。这会导致两个问题:
- 析构函数终止对同一地址两次调用
delete
。 - 为
a2
分配的初始内存永远不会被释放。
当您的成员变量之一是std::string
时,也会发生类似的情况。
问题可能在这里:
myfile.write(reinterpret_cast<char *>(&miperro5[i]), sizeof(Perro));
你正在写一个结构体Perro
到文件,但你必须确保你写得正确,因为一般情况下,像
struct Foo
{
std::string str;
};
不会像您想象的那样写入磁盘。只有只包含普通旧数据(POD)的结构可以像您所做的那样编写,其余的必须手动编写每个字段。如果您想通过对象序列化简化您的生活,请查找boost::serialization
。
main.cpp
#include <stdio.h>
#include <iostream>
#include <fstream>
#include "Perro.hpp"
using std::cout;
using std::endl;
int main(int argc, char **argv)
{
Perro miperro5[5];
Perro miperro6[5];
miperro5[2].nombre = "lucky";
std::ofstream myfile;
myfile.open("example.bin", std::ios::out | std::ios::app | std::ios::binary);
for (int i = 0; i < 5; i++){
myfile << miperro5[i];
}
myfile.close();
std::ifstream myfile2;
myfile2.open("example.bin", std::ios::in | std::ios::binary);
for (int j = 0; j < 5; j++){
myfile2 >> miperro6[j];
}
myfile2.close();
for (int z = 0; z < 5; z++){
cout << miperro6[z].nombre << endl;
}
std::cin.get();
return 0;
}
Perro.hpp
#ifndef PERRO_HPP
#define PERRO_HPP
#include <string>
#include <ostream>
#include <istream>
class Perro
{
public:
Perro() {};
~Perro() {};
void ladrar();
void comer();
std::string nombre;
int edad;
int arra[2];
};
std::ostream & operator<<(std::ostream & ostrm, const Perro & src)
{
// nombre
std::string::size_type cch = src.nombre.length();
ostrm // std::string is not a primitive type, so we need to do a (sort of) deep copy.
.write(reinterpret_cast<const char *>(&cch), sizeof(std::string::size_type))
<< src.nombre.c_str() // or use unformatted output `write`
;
// edad, arra[2]
ostrm
.write(reinterpret_cast<const char *>(&src.edad), sizeof(int)) // edad
.write(reinterpret_cast<const char *>(&src.arra), sizeof(int) * 2) // arra[2]
;
return ostrm;
}
std::istream & operator>>(std::istream & istrm, Perro & dst)
{
// Read the string back.
std::string::size_type cchBuf;
istrm.read(reinterpret_cast<char *>(&cchBuf), sizeof(std::string::size_type));
char * buf = new char[cchBuf];
istrm.read(buf, cchBuf);
dst.nombre.assign(buf, cchBuf);
delete [] buf;
// Read other data members of primitive data type.
istrm
.read(reinterpret_cast<char *>(&dst.edad), sizeof(int)) // edad
.read(reinterpret_cast<char *>(&dst.arra), sizeof(int) * 2) // arra[2]
;
// Return the stream so it can be examined on its status.
return istrm;
}
#endif // PERRO_HPP