I tried to make a program to write lists and save them to binary files so nobody can change it and its size less than the text file. I tried to use three vectors inside each other, but when reading it gives a segmentation fault.
Here is the writing code:
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
vector<vector<vector<string>>> test;
int main() {
test.push_back({{"Hello"}});
cout << test[0][0][0];
ofstream otst("test.bin",ios::binary);
otst.write((char*)&test,sizeof(test));
return 0;
}
And here is the reading code:
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
vector<vector<vector<string>>> test;
int main() {
ifstream tst("test.bin",ios::binary);
tst.read((char*)&test,sizeof(test));
return 0;
}
CodePudding user response:
You are trying to write()
and read()
the outer vector
object exactly as it appears in memory. That will not work, since it contains pointers to data that is stored elsewhere in memory. You must serialize its data instead, and then deserialize it in the reading code, eg:
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cstdint>
using namespace std;
template<typename T>
void write(ofstream &out, const T &value)
{
out.write(reinterpret_cast<const char*>(&value), sizeof(value));
}
void write(ofstream &out, const string &value)
{
uint32_t size = str.size();
write(out, size);
if (size > 0) {
out.write(str.c_str(), size);
}
}
template<typename T>
void write(ofstream &out, const vector<T> &vec)
{
uint32_t size = vec.size();
write(out, size);
for(const auto &elem : vec) {
write(out, elem);
}
}
int main()
{
vector<vector<vector<string>>> test;
test.push_back({{"Hello"}});
cout << test[0][0][0];
ofstream otst("test.bin", ios::binary);
otst.exceptions(ofstream::failbit);
write(otst, test);
return 0;
}
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cstdint>
using namespace std;
template<typename T>
void read(ifstream &in, T &value)
{
in.read(reinterpret_cast<char*>(&value), sizeof(value));
}
void read(ifstream &in, string &str)
{
uint32_t size;
read(in, size);
str.resize(size);
if (size > 0) {
in.read(&str[0]/* or: str.data() */, size);
}
}
template<typename T>
void read(ifstream &in, vector<T> &vec)
{
uint32_t size;
read(in, size);
vec.resize(size);
for(auto &elem : vec) {
read(in, elem);
}
}
int main()
{
vector<vector<vector<string>>> test;
ifstream itst("test.bin",ios::binary);
itst.exceptions(ifstream::failbit);
read(itst, test);
return 0;
}
UPDATE:
If you can use Boost, it has its own serialization framework, which natively supports serializing vectors. See C Boost serialization of a matrix of vectors
CodePudding user response:
I had a similar issue with writing 3d arrays from the heap to memory and reading it. I don't know if it would solve your issue but it's possible that each vector dimension contains a pointer to another vector until the program gets to the base vector so the data that is written is just the pointer of the vectors which would not be part of the program when you read from the binary file. This would result in the program writing pointers to unallocated memory which would cause a segmentation fault. Another possible problem is that you read to sizeof(test) which might not have allocated space for non-existent elements(I haven't worked with vectors a ton so I don't know how stack allocation works with them). My money is on the first idea though which is good because it is also easier to fix. Just right simple recursion in your write process for example:
int main() {
fstream fs;
fs.open("test.bin",ios::out | ios::binary);
vector<vector<vector<string>>> test;
for(int h = 0; h < test[0].size(); h ) {
for(int w = 0; w < test[0][0].size(); w ) {
for(int t = 0; t < test[0][0][0].size(); t ) {
fs.write((char*)&test[h][w][t], sizeof(test));
}
}
}
return 0;
}
I would recommend however, that if you can yous should just use a really large array like a [1000][1000][1000] array. It is easier to use set amounts of numbers.