I'm trying to create a iterator to go through my file. My file is binary and have int values inside, so in my point of view, it should work like that. But I'm getting errors says "invalid use of data-member 'IntFile::file' "So i marked in code where I'm getting errors. How can I manage it?
#include <iostream>
#include <cstdio>
using namespace std;
class IntFile
{
public:
int index;
FILE* file; // Error here
IntFile() {}
~IntFile() {}
int mnumbers[10];
int mnumbers2[10];
int value;
// And this whole class does not work
class iterator
{
bool operator ++ ()
{
file = fopen ("text.txt", "r+b");
fseek (file, 4*index, SEEK_CUR);
fclose(file);
}
bool operator -- ()
{
file = fopen ("text.txt", "r+b");
fseek (file, (-4)*index, SEEK_CUR);
fclose(file);
}
/*
iterator begin()
{
return ;
}
iterator end()
{
return ;
}
*/
};
};
I'm getting errors says "invalid use of data-member 'IntFile::file'"
IntFile::iterator doesn't have a data member file, nor does it implicitly have a reference to an instance of IntFile (as would be the case in, say, Java).
IntFile::iterator needs a reference to IntFile to be able to use that data member:
class iterator
{
explicit iterator(IntFile &file) : file(file) {}
// Your other code
private:
IntFile &file;
};
Then you will be able to access file.file, file.index, etc.
However, this will break down if you create multiple iterators and expect them to point to different places in the file because with this approach they all share a single file handle, and therefore a single position within that file. You can have each iterator keep track of its own position and seek there before each operation (not thread-safe) or you can duplicate the file handle for each iterator (consumes an additional file descriptor per iterator).
Or, it may be much easier to just memory-map the file and use a pointers into the mapped address space as your iterators.
Related
I'm writing data (structure) into file using vector, and when I attempt to retrieve data using vector iterator and it gives me: "Vector iterator is not dereferenceable."
This is my code:
void CProgram_1_STLDlg::OnBnClickedBtnView()
{
// TODO: Add your control notification handler code here
CFile file;
CFileException e;
studentVector::iterator sit;
studentVector::iterator sBegin = sVector.begin();
studentVector::iterator sEnd = sVector.end();
CString path = _T("D:\\Student.txt");
if ( file.Open(path, CFile::modeRead, &e) ) {
while ( file.Read( (char *)&sVector, sizeof(sVector)) ) {
AfxMessageBox(_T("File opened in read mode."), MB_ICONINFORMATION);
AfxMessageBox(_T("ID:\t")+sit->id+L"\nName:\t"
+sit->name+L"\nMarks:\t"+sit->marks+L
"\nPercentage:\t"+sit->per+L"\nState:\t"+sit->state);
sit++;
}
//file.Read( (char *)&sData, sizeof(sData));
/*for ( sIterator = sVector.begin(); sIterator != sVector.end(); sIterator++ ) {
//AfxMessageBox(_T("ID:\t")+sIterator->id+L
"\nName:\t"+sIterator->name+L"\nMarks:\t"
+sIterator->marks+L"\nPercentage:\t"+sIterator->per+L
"\nState:\t"+sIterator->state);
//AfxMessageBox(_T("Hello..Testing...!"));
}
*/
} else {
AfxMessageBox(_T("Error! Unable to open file."), MB_ICONERROR);
}
}
Now I don't know how to resolve this error.
Note: Some of links I refer which google gave me, but I couldn't able to solve my problem.
You cannot simply overwrite the memory of a vector. That is pretty much guaranteed to corrupt your process.
Furthermore, you never assign anything to sit and yet expect it to contain something sensible.
You need to parse the data in Student.txt and use vector's member functions to fill it with sensible data. The assignment will probably tell you what the file looks like so that you can parse it.
A simple vector like
vector<char> cvec
could be overwritten
so something like
vector<char> cvec;
cvec.resize(100);
for(char i=0;i<100;i++)
cvec[i]=i;
will work.
If you resize to correct size. Otherwise you will corrupt memory
sizeof(sVector) will deliver the size of the vector class.
this is not related to the data since data inside the vector class is nothing more than a pointer.
example:
class simpleVector;
{
public:
simpleVector(unigned int size)
{
p=new int[size];
}
int* p;
}
func()
{
simpleVector v1(10);
simpleVector v2(100000);
printf("size v1= %d, Size v2= %d", sizeof(v1),sizeog(v2));
}
I have not checked, what sizeof will deliver for this class, but it definitely will be constant. Independent from the size that is given to constructor
An Iterator is an accessor to the Vector
but it needs to be initialized.
In the code above sit is not assigned to something. So you are not able to access something valid.
from the code line
AfxMessageBox(_T("ID:\t")+sit->id+L"\nName:\t"+sit->name+L"\nMarks:\t"+sit->marks+L"\nPercentage:\t"+sit->per+L"\nState:\t"+sit->state);
I see the vector shall contain a complex data type build from several strings.
so a vector element probably looks like
class student
{
std::string id;
std::string name;
std::string marks;
std::string per;
std::string state;
};
this is in minimum the information hold by each vector element.
usually strings have the property to have different length.
While id might be always of same length name probably don't.
Since it is not fixed length
even
file.Read( (char *)&sVector, sizeof(student))
would not work.
so I would suggest to add a reader to the 'Student' Class:
class student
{
std::string id;
std::string name;
std::string marks;
std::string per;
std::string state;
bool ReadElemFromFile(CFile& file)
{
id=ReadStringFromFile(file);
name=ReadStringFromFile(file);
marks=ReadStringFromFile(file);
per=ReadStringFromFile(file);
state=ReadStringFromFile(file);
if(id.empty()||name.empty()||marks.empty()||per.empty()||state.empty())
return false;
return true;
}
std::string ReadStringFromFile(CFile% file)
{
char c;
std::string s;
do
{
file.read(&c,1);
s+=c;
}
while(c!='\0')
return s;
}
};
I know reading that way is not the most performant way to do it, but it shows,that the string terminator stored to file indicates the length of each string
now back to your code
void CProgram_1_STLDlg::OnBnClickedBtnView()
{
// TODO: Add your control notification handler code here
CFile file;
CFileException e;
student* sit=new Student;
studentVector.clear();
CString path = _T("D:\\Student.txt");
if ( file.Open(path, CFile::modeRead, &e) ) {
while ( sit->ReadElemFromFile(CFile& file)) {
AfxMessageBox(_T("File opened in read mode."), MB_ICONINFORMATION);
AfxMessageBox(_T("ID:\t")+sit->id+L"\nName:\t"+sit->name+L"\nMarks:\t"+sit->marks+L"\nPercentage:\t"+sit->per+L"\nState:\t"+sit->state);
studentVector.push_back(*sit);
}
} else {
AfxMessageBox(_T("Error! Unable to open file."), MB_ICONERROR);
}
delete stud;
}
..."attempt to retrieve data using vector iterator and it gives me Vector iterator is not dereferenceable"...
Iterators are pointer-like objects, however unlike raw pointers, they prevent dereferencing (accessing of the value they point to) if they are "dangling".
In your case iterator sit is not initialized, not as, for example iterator sBegin = sVector.begin();, that is assigned to point to the beginning of the vector sVector.
Thus when you try to access an iterator that does not point to a valid value, you get an error.
In addition to that, to store an element to a vector you should use its member functions, not passing its address, as you do in your while loop.
I have a class called Game which contains the following:
vector<shared_ptr<A>> attr; // attributes
D diff; // differences
vector<shared_ptr<C>> change; // change
My question is, how can I write these (save) to a file and read/load it up later?
I thought about using a struct with these in it, and simply saving the struct but I have no idea where to start.
This is my attempt so far, with just trying to save change. I've read up a lot on the issue and my issue (well one of them, anyway) here seems to be that I am storing pointers which after closing the program would be invalid (compounded by the fact that I also free them before exiting).
/* Saves state to file */
void Game::saveGame(string toFile) {
ofstream ofs(toFile, ios::binary);
ofs.write((char *)&this->change, sizeof(C));
/* Free memory code here */
....
exit(0);
};
/* Loads game state from file */
void Game::loadGame(string fromFile) {
ifstream ifs(fromFile, ios::binary);
ifs.read((char *)&this->change, sizeof(C));
this->change.toString(); // display load results
};
Can anyone guide me in the right direction for serializing this data? I'd like to use only standard packages, so no boost.
Thanks.
I have no idea how is implemented classes A, C or D, but that is the first question: how to serialize an object of that class. For the C case, you need to implement something like this:
std::ostream& operator <<(std::ostream& os, const C& c) {
// ... code to serialize c to an output stream
return os;
}
std::istream& operator >>(std::istream& is, C& c) {
// ... code to populate c contents from the input stream
return is;
}
or, if you prefer, create a write() and read() function for that class.
Well, if you want to serialize a vector<shared_ptr<C>> looks obvious you don't want to serialize the pointer, but the contents. So you need to dereference each of those pointers and serialize. If the size of the vector is not known before loading it (i.e., is not always the same), you'll need to store that information. Then, you can create a pair of functions to serialize the complete vector:
std::ostream& operator <<(std::ostream& os, const std::vector<std::shared_ptr<C>>& vc) {
// serialize the size of the vector using << operator
// for each element of the vector, let it be called 'pc'
os << *pc << std::endl; // store the element pointed by the pointer, not the pointer.
return os;
}
std::istream& operator >>(std::istream& is, std::vector<std::shared_ptr<C>>& c) {
// read the size of the vector using >> operator
// set the size of the vector
// for each i < sizeo of the vector, let 'auto &pc = vc[i]' be a reference to the i-th element of the vector
C c; // temporary object
is >> c; // read the object stored in the stream
pc = std::make_shared<C>(c); // construct the shared pointer, assuming the class C has copy constructor
return is;
}
And then,
/* Saves state to file */
void Game::saveGame(string toFile) {
ofstream ofs(toFile);
ofs << change;
....
};
/* Loads game state from file */
void Game::loadGame(string fromFile) {
ifstream ifs(fromFile);
ifs >> change;
};
I know there are a lot of things you still need to resolve. I suggest you to investigate to resolve them so you understand well how to solve your problem.
Not only are you saving pointers, you're trying to save a shared_ptr but using the wrong size.
You need to write serialization functions for all your classes, taking care to never just write the raw bits of a non-POD type. It's safest to always implement member-by-member serialization for everything, because you never know what the future will bring.
Then handling collections of them is just a matter of also storing how many there are.
Example for the Cs:
void Game::save(ofstream& stream, const C& data)
{
// Save data as appropriate...
}
void Game::saveGame(string toFile) {
ofstream ofs(toFile, ios::binary);
ofs.write((char *)change.size(), sizeof(change.size());
for (vector<shared_ptr<C>>::const_iterator c = change.begin(); c != change.end(); ++c)
{
save(ofs, **c);
}
};
shared_ptr<C> Game::loadC(ofstream& stream)
{
shared_ptr<C> data(new C);
// load the object...
return data;
}
void Game::loadGame(string fromFile) {
change.clear();
size_t count = 0;
ifstream ifs(fromFile, ios::binary);
ifs.read((char *)&count, sizeof(count));
change.reserve(count);
for (int i = 0; i < count; ++i)
{
change.push_back(loadC(ifs));
}
};
All the error handling is missing of course - you would need to add that.
It's actually a good idea to at least start with text storage (using << and >>) instead of binary. It's easier to find bugs, or mess around with the saved state, when you can just edit it in a text editor.
Writing your own serialization is quite a challenge. Even if you do not use boost serializatoin I would recommend you learn how to use it and comprehend how it works rather than discovering it yourself.
When serializing you finally end up with a buffer of data of which content you have very vague idea. You have to save everything you need to be able to restore it. You read it chunk by chunk. Example (not compiled, not tested and not stylish ):
void save(ostream& out, const string& s)
{
out << s.size();
out.write(s.c_str(), s.size());
}
void load(istream& in, string& s)
{
unsigned len;
in >> len;
s.resize(len);
in.read((char*)s, len);
}
struct Game
{
void save(ostream& out)
{
player.save(out);
};
void load(istream& in)
{
player.load(in);
}
};
struct Player
{
void save(ostream& out)
{
// save in the same order as loading, serializing everything you need to read it back
save(out, name);
save(out, experience);
}
void load(istream& in)
{
load(in, name);
load(in, experience); //
}
};
I do not know why you would do it to yourself instead of using boost but those are some of the cases you should consider:
- type - you must figure out a way to know what "type of change" you actually have there.
- a string (vector, whatever) - size + data (then the first thing you read back from the string is the length, you resize it and copy the "length" number of characters)
- a pointer - save the data pointed by pointer, then upon deserialization you have to allocate it, construct it (usually default construct) and read back the data and reset the members to their respective values. Note: you have to avoid memory leakage.
- polymorphic pointer - ouch you have to know what type the pointer actually points to, you have to construct the derived type, save the values of the derived type... so you have to save type information
- null pointer... you have to distinguish null pointer so you know that you do not need to further read data from the stream.
- versioning - you have to be able to read a data after you added/removed a field
There is too much of it for you to get a complete answer.
I have to copy column info from a database to a struct, the problem is that it takes over 5000 iterations and is very slow. Is there any better way?
The code used is in the .h file:
struct sFieldDef
{
CString m_strQualifier;
CString m_strOwner;
CString m_strTableName;
CString m_strColumnName;
int m_nDataType;
CString m_strTypeName;
long m_lPrecision;
long m_lLength;
int m_nScale;
int m_nRadix;
int m_nNullable;
};
The code used in the .cpp file:
sFieldDef sTempField;
CColumns rsColumns(m_pDatabase);
rsColumns.Open(CRecordset::snapshot);
while( !rsColumns.IsEOF() )
{
sTempField.m_strQualifier=rsColumns.m_strQualifier;
sTempField.m_strOwner=rsColumns.m_strOwner;
sTempField.m_strTableName=rsColumns.m_strTableName;
sTempField.m_strColumnName=rsColumns.m_strColumnName;
sTempField.m_nDataType=rsColumns.m_nDataType;
sTempField.m_strTypeName=rsColumns.m_strTypeName;
sTempField.m_lPrecision=rsColumns.m_lPrecision;
sTempField.m_lLength=rsColumns.m_lLength;
sTempField.m_nScale=rsColumns.m_nScale;
sTempField.m_nRadix=rsColumns.m_nRadix;
sTempField.m_nNullable=rsColumns.m_nNullable;
pArrFiels->Add(sTempField);
rsColumns.MoveNext();
}
You seem to be copying and storing everything in an array of structs, where each struct has identical members with the corresponding record. Usually we use arrays through iterators. So why not provide an iterator to your record-set and avoid copying altogether? You could roughly start like this:
template <typename RS>
class rs_iterator
{
RS& rs;
public:
rs_iterator(RS& rs) : rs{rs} { }
const RS& operator*() { return rs; }
rs_iterator& operator++() { return rs.MoveNext(), *this; }
// ...
}
So you not only provide a convenient and standard interface to an array-like data source like a record-set, but you can use it directly in STL-like algorithms requiring bidirectional iterators.
If your CRecordset supports random access, then so would your iterator, easily. Otherwise, random access provision by itself is a good reason to copy (e.g. to sort columns).
I am trying to read/deserialize a list of elements from a file (and then filter out some of them). It is a useful approach to use an iterator for this purpose?
My current try is
#include <boost/iterator/iterator_adaptor.hpp>
class ReadIterator : public boost::iterator_adaptor<ReadIterator, Elem *, boost::single_pass_traversal_tag>
{
public:
explicit ReadIterator(const char *filename) : reader(filename) {}
private:
friend class boost::iterator_core_access;
void increment() {
this->base_reference() = reader.readNext();
}
Reader reader;
};
This does not properly deallocate memory (e.g., readNew returns a pointer to a new Elem), what is the right way to do this? Also, how would one actually use such an iterator, how can the end be determined? Or is there a better approach than using an iterator?
The easy way to do this is to use the std::istream_iterator
std::vector<YourObjectClass> data;
std::remove_copy_if(std::istream_iterator<YourObjectClass>(file),
std::istream_iterator<YourObjectClass>(),
std::back_inserter(data),
YourFilter
);
The standard algorithm copies objects (of type YourObjectClass) from the input file and places them into the vector data if the filter functor returns true.
The only conditions are:
YourObjectClass must have an input stream operator
YourFilter must overload the operator() for objects of YourObjectClass or be a function that takes a parameter of type YourObjectClass.
Simple Working Example:
My object is a line.
Filter out line(s) that start with the letter 'A'
Exmpale:
#include <vector>
#include <string>
#include <fstream>
#include <iterator>
#include <algorithm>
struct Line
{
std::string data;
};
std::istream& operator>>(std::istream& stream, Line& line)
{
return std::getline(stream, line.data);
}
struct AFilter
{
bool operator()(Line const& line) const
{
return line.data.size() > 0 && line.data[0] == 'A';
}
};
int main()
{
std::ifstream file("Plop");
std::vector<Line> data;
std::remove_copy_if(std::istream_iterator<Line>(file),
std::istream_iterator<Line>(),
std::back_inserter(data),
AFilter()
);
}
Rather than readNext() returning a raw pointer to an element, can you construct the call so that it returns a reference-counted smart-pointer that will automatically release it's resources when the reference-count to the pointer goes to zero? Either that, or you're going to have to find a way to fetch the pointer back so you can call delete on it before you allocate more memory via the next call to readNext() when increment() is called again.
As for the "end", what you could do in this case is have some test in your Reader class that detects if you've reached the end of the file or some other ending scenario. If you have, then return false, otherwise return true. For example:
bool increment()
{
if (reader.not_end_of_file())
{
this->base_reference() = reader.readNext();
return true;
}
return false;
}
So now you could call increment() in some type of loop, and you'll know when you've hit the end-of-file or some other ending because the function will return false.
Using an iterator for the purpose is fine. You haven't given any indication that the existing istream_iterator won't work for your purpose though. At least in most cases, you can just write an operator>> for a single element, and use std::istream_iterator to read a list of those elements from the file.
I'm trying to port some of my c++ code into c. I have the following construct
class reader{
private:
FILE *fp;
alot_of_data data;//updated by read_until() method
public:
reader(const char*filename)
read_until(some conditional dependent on the contents of the file, and the arg supplied)
}
Im then instantiating hundreds of these object and iterate over them using several 'read_until()' for each file until allfiles is at eof.
I'm failing to see any clever way to do this in c, the only solution I can come up with is making an array of FILE pointers, and do the same with all the private member data from my class.
But this seems very messy, can I implement the functionality of my class as a function pointer, or anything better, I think I'm missing a fundamental design pattern?
The files are way to big to have all in memory, so reading everything from every file is not feasible
Thanks
You create an abstract data type:
typedef struct {
FILE *fp;
alot_of_data data;//updated by read_until() method
} reader;
void init_reader(reader* that, const char* filename);
void read_until(reader* that, some conditional dependent on the contents of the file, and the arg supplied)
Then you can create and use objects of this type just as with objects of the class, except that, instead of obj.func(), you write func(&obj):
reader r;
init_reader(&r, "blah.txt");
read_until(&r, /* ... */);
The easiest way is to just convert the data into a struct:
struct reader
{
FILE *file;
alot_of_data data;
};
Then define ordinary functions, that take a struct reader as their first argument:
int reader_construct(struct reader *r, const char *filename)
{
if((r->file = fopen(filename, "rt")) == NULL)
return 0;
/* do other inits */
return 1;
}
and the reader function becomes:
int read_until(struct reader *r, arguments)
{
/* lots of interesting code */
}
Then just have an array of structures, call reader_construct() on them and then do the read_until() calls as required.
You could of course opt for a more dynamic constructor, that returns the "object":
struct reader * reader_new(const char *filename)
{
struct reader *r = malloc(sizeof *r);
if(r == NULL)
return NULL;
if(reader_construct(r, filename))
return r;
return NULL;
}
The principle of information hiding is the same, regardless of the language you use. Just move the stuff you want to hide into the source file:
// reader.h
typedef struct reader reader;
reader* new_reader(const char*filename);
void read_until(reader*, ...);
// reader.c
struct reader {
FILE *fp;
alot_of_data data;//updated by read_until() method
};
reader *new_reader(const char*filename) { ... }
void read_until(reader*, ...) { ... }
You could always create a structure to hold all the related information, and then loop over that... Just an idea... (I think C supports structures - it's been a while...)