class MyClass
{
private:
AnotherClass obj;
float d;
int k;
public:
MyClass(float d = 0.3, int k = 10);
virtual ~MyClass();
// other methods goes here
}
Is it possible to have a method that allow this class (MyClass) to save to its attribute values on the disk (hard drive) void storeOnDisk(string path){...} and another method which allow to load the attribute values from disk void loadFromDisk(string path) ?
If it is possible, should I also call loadFromDisk(path) in the constructor of MyClass (create another constructor maybe), and storeOnDisk(path) in the destructor of MyClass so that all current values can be saved when quitting the program that instanciated MyClass ?
It depends on what exactly you want to achieve. However, usually, you'd not like to have such things in ctor/dtor since in C++ "copies" and "temporary objects" show up sometimes. Ctors/dtors are called when they are created/removed, just like regular objects, and it would also touch the files unless you prepare the code really well.
Often it is somewhat easier to keep a separate class that handles the reading/writing. Imagine a MyClassStorage class that would be a friend of the MyClass and that would contain only two methods: MyClass read(path) and write(path MyClass&).
If you like having it in single class or if you don't want to do everything manually, you can look at some serialization frameworks like Boost::Serialization. There are many short and easy examples on how to handle it, but - still - you'll have to read a bit about it first.
EDIT:
See http://www.boost.org/doc/libs/1_45_0/libs/serialization/doc/tutorial.html and the "A very simple case" section. It shows how to read/write a gps_position class. Note that this class iteself is very simple except that it contains an additional serialize function. This function works 'automagically' both as reader and writer. Since usually you want to read the same fields as you wanted to write, there's not need to say it twice (instead of saying read-A-B-C and write-A-B-C you say: handleThemForMe-A-B-C).
Then, in main you have example of usage. The text_oarchive and text_iarchive act as output and input files. Some gps_position object is created and named g, then saved to a file called filename, and then it is read back from the file as newg.
Actually, the ofstream line is somewhat too early and may be misleading. It is only for creating the oarchive and can be safely moved down like the ifstream/iarchive. It could look like that:
// create class instance
const gps_position g(35, 59, 24.567f);
/// ....
// save data to archive
{
// create and open a character archive for output
std::ofstream ofs("filename");
boost::archive::text_oarchive oa(ofs);
// write class instance to archive
oa << g;
// archive and stream closed when destructors are called
}
/// ....
// ... some time later restore the class instance to its orginal state
gps_position newg;
{
// create and open an archive for input
std::ifstream ifs("filename");
boost::archive::text_iarchive ia(ifs);
// read class state from archive
ia >> newg;
// archive and stream closed when destructors are called
}
It is and you may use http://www.boost.org/doc/libs/1_34_0/libs/serialization/doc/index.html. (It is doing even more you expect)
Related
I have a file_manager class that tracks the files in a given directory. I use it as the model for a file UI similar to Windows Explorer or macOS Finder. The file_manager has various find() methods to allow clients to ask for handles to files, and those methods return an optional which will be empty if no files matched that search criteria.
Since files can be deleted from the directory at any time without our knowledge, there's a comment on the find() methods saying that you shouldn't retain the pointers they give you. Instead, you should just query the file_manager again later (e.g., once per frame/once per UI update/etc.). This rule helps prevent having to wrap every future use of the file_handle in something like an is_still_on_disk() check.
Here's what the code currently looks like:
struct file_handle {
std::string path;
std::string contents;
// Other metadata here
};
class file_manager {
public:
file_manager(std::string directory_to_manage);
// Clients shouldn't retain this pointer, because the file could
// disappear from disk at any time.
// Empty if we were unable to find a file with this name.
optional<const file_handle *> find_file_by_name(std::string file_name) const;
optional<const file_handle *> find_file_modified_before(time_t time) const;
// other find_xxx() methods here
// Examines the disk to add/remove from all_known_files to match the
// current state of the directory.
// Only called at well-defined times, from the same thread that uses
// the "find" methods.
void update();
private:
std::list<file_handle> all_known_files;
}
Is there any way to codify this "do not retain" rule such that you'd get a compile error (or failing that, a runtime assertion failure) if you stored the return value of the "find" method as a member variable? (Preventing it from being a static variable would be nice too, if possible.)
That is, I'd like to be able to have the file_manager::find_xxx() methods instead return an optional "un-retainable" wrapper... something like this:
class file_manager {
. . .
optional<cant_retain_me<file_handle>> find_file_by_name(std::string file_name) const;
. . .
}
...where the cant_retain_me wrapper would allow this code to work:
void do_stuff() {
auto optional_file = my_file_manager.find_file_by_name("foo.txt");
if(optional_file.has_value()) {
cant_retain_me<file_handle> handle = *optional_file;
// use handle as though it were a normal file_handle or file_handle *
}
}
...but would break this code:
class client {
client() {
auto optional_file = my_file_manager.find_file_by_name("foo.txt");
if(optional_file.has_value()) {
my_handle = *optional_file;
} else { /* use some fallback value */ }
}
void do_stuff() {
// Try to use my_handle as though it were a normal file_handle or file_handle *
}
cant_retain_me<file_handle> my_handle;
}
Two ideas I had considered for the wrapper:
Prevent the wrapper class from being instantiated on the heap. This would help a little (it's better than nothing!), but doesn't prevent the use shown in client above.
Make the wrapper class move-only (delete the copy constructor). I think this would work, in that it would at least force clients to write some very awkward code to store the handle as a member... but I don't write much code with explicit moves, so I'm not entirely sure if this would have the desired effect.
I realize in a language with memcpy() there's never going to be a way to fully prohibit clients from bad behavior, but I'd like to make it misusing the API as obvious a code smell as possible.
I have a class A which handles file by opening, reading and closing. I also have another class B that use A to read file. B has instance of A as private member data. I want to reuse the a and use it to read multiple files using this instance. I also read some where that we cannot copy any of the stream. So my question is how can I handle class A to read multiple files in B?
class A{
A(std::string s){
f.open(s);
}
void read_file(){
/// read file
// close after reading
f.close();
}
private:
std::ifstream f;
};
class B{
B(std::string s_):a(s_){}
void read_multiple_files(){
a.read_file();
// now lets read another file
a = A("another_file_1.txt");
a.read_file();
////////////////////
// now lets read another file
a = A("another_file_2.txt");
a.read_file();
}
private:
A a
};
This is probably a design issue. There seems no reason for B to hold an instance of A unless it needs to keep a file handle across different method calls.
Instead, simply create an A to read each file:
class B {
void read_multiple_files() {
// read our files
auto result = A("another_file_1.txt").read_file();
auto result_2 = A("another_file_2.txt").read_file();
...
}
}
In my current project, I have a lot of binary files of different formats. Several of them act as simple archives, and therefore I am trying to come up with a good approach for passing extracted file data on to other classes.
Here's a simplified example of my current approach:
class Archive {
private:
std::istream &fs;
void Read();
public:
Archive(std::istream &fs); // Calls Read() automatically
~Archive();
const char* Get(int archiveIndex);
size_t GetSize(int archiveIndex);
};
class FileFormat {
private:
std::istream &fs;
void Read();
public:
FileFormat(std::istream &fs); // Calls Read() automatically
~FileFormat();
};
The Archive class basically parses the archive and reads the stored files into char pointers.
In order to load the first FileFormat file from an Archive, I would currently use the following code:
std::ifstream fs("somearchive.arc", std::ios::binary);
Archive arc(fs);
std::istringstream ss(std::string(arc.Get(0), arc.GetSize(0)), std::ios::binary);
FileFormat ff(ss);
(Note that some files in an archive could be additional archives but of a different format.)
When reading the binary data, I use a BinaryReader class with functions like these:
BinaryReader::BinaryReader(std::istream &fs) : fs(fs) {
}
char* BinaryReader::ReadBytes(unsigned int n) {
char* buffer = new char[n];
fs.read(buffer, n);
return buffer;
}
unsigned int BinaryReader::ReadUInt32() {
unsigned int buffer;
fs.read((char*)&buffer, sizeof(unsigned int));
return buffer;
}
I like the simplicity of this approach but I'm currently struggling with a lot of memory errors and SIGSEGVs and I'm afraid that it's because of this method. An example is when I create and read an archive repeatedly in a loop. It works for a large number of iterations, but after a while, it starts reading junk data instead.
My question to you is if this approach is feasible (in which case I ask what I am doing wrong), and if not, what better approaches are there?
The flaws of code in the OP are:
You are allocating heap memory and returning a pointer to it from one of your functions. This may lead to memory leaks. You have no problem with leaks (for now) but you must have such stuff in mind while designing your classes.
When dealing with Archive and FileFormat classes user always has to take into account the internal structure of your archive. Basically it compromises the idea of data incapsulation.
When user of your class framework creates an Archive object, he just gets a way to extract a pointer to some raw data. Then the user must pass this raw data to completely independent class. Also you will have more than one kind of FileFormat. Even without the need to watch for leaky heap allocations dealing with such system will be highly error-prone.
Lets try to apply some OOP principles to the task. Your Archive object is a container of Files of different format. So, an Archive's equivalent of Get() should generally return File objects, not a pointer to raw data:
//We gonna need a way to store file type in your archive index
enum TFileType { BYTE_FILE, UINT32_FILE, /*...*/ }
class BaseFile {
public:
virtual TFileType GetFileType() const = 0;
/* Your abstract interface here */
};
class ByteFile : public BaseFile {
public:
ByteFile(istream &fs);
virtual ~ByteFile();
virtual TFileType GetFileType() const
{ return BYTE_FILE; }
unsigned char GetByte(size_t index);
protected:
/* implementation of data storage and reading procedures */
};
class UInt32File : public BaseFile {
public:
UInt32File(istream &fs);
virtual ~UInt32File();
virtual TFileType GetFileType() const
{ return UINT32_FILE; }
uint32_t GetUInt32(size_t index);
protected:
/* implementation of data storage and reading procedures */
};
class Archive {
public:
Archive(const char* filename);
~Archive();
BaseFile* Get(int archiveIndex);
{ return (m_Files.at(archiveIndex)); }
/* ... */
protected:
vector<BaseFile*> m_Files;
}
Archive::Archive(const char* filename)
{
ifstream fs(filename);
//Here we need to:
//1. Read archive index
//2. For each file in index do something like:
switch(CurrentFileType) {
case BYTE_FILE:
m_Files.push_back(new ByteFile(fs));
break;
case UINT32_FILE:
m_Files.push_back(new UInt32File(fs));
break;
//.....
}
}
Archive::~Archive()
{
for(size_t i = 0; i < m_Files.size(); ++i)
delete m_Files[i];
}
int main(int argc, char** argv)
{
Archive arch("somearchive.arc");
BaseFile* pbf;
ByteFile* pByteFile;
pbf = arch.Get(0);
//Here we can use GetFileType() or typeid to make a proper cast
//An example of former:
switch ( pbf.GetFileType() ) {
case BYTE_FILE:
pByteFile = dynamic_cast<ByteFile*>(pbf);
ASSERT(pByteFile != 0 );
//Working with byte data
break;
/*...*/
}
//alternatively you may omit GetFileType() and rely solely on C++
//typeid-related stuff
}
Thats just a general idea of the classes that may simplify the usage of archives in your application.
Have in mind though that good class design may help you with memory leaks prevention, code clarification and such. But whatever classes you have you will still deal with binary data storage problems. For example, if your archive stores 64 bytes of byte data and 8 uint32's and you somehow read 65 bytes instead of 64, the reading of the following ints will give you junk. You may also encounter alignment and endianness problems (the latter is important if you applications are supposed to run on several platforms). Still, good class design may help you to produce a better code which addresses such problems.
It is asking for trouble to pass a pointer from your function and expect the user to know to delete it, unless the function name is such that it is obvious to do so, e.g. a function that begins with the word create.
So
Foo * createFoo();
is likely to be a function that creates an object that the user must delete.
A preferable solution would, for starters, be to return std::vector<char> or allow the user to pass std::vector<char> & to your function and you write the bytes into it, setting its size if necessary. (This is more efficient if doing multiple reads where you can reuse the same buffer).
You should also learn const-correctness.
As for your "after a while it fills with junk", where do you check for end of file?
Here is what i am trying to do.
I have Three Classes:
1) CEngine
2) CLogManager
3) CWindowGL
Ad1.
This class 'does' the tricky things to get the game engine going,
an application utilizing it, can call only few public members to
get the game going -
class CEngine
{
public:
CEngine();
~CEngine(); // should this go to private?
bool Init(width,height,...);
void Destroy();
void Run();
bool LoadMap(...);
private:
CLogManager *m_pLogManager;
CWindowGL *m_pWindowManager
}
// Example usage
CEngine *Engine=new CEngine;
Engine->Initialize(...)
Engine->LoadMap(...)
Engine->Run()
Engine->Destroy()
delete(Engine)
Ad2.
This class controls the logging facility
it just allows me to dump some log into the log data file:
class CLogManager
{
public:
CLogManager();
~CLogManager();
void Write(const char *fmt,...);
private:
FILE *fp;
std::string m_sFileName; // unique filename generated at the constructor
SYSTEMTIME m_tSystemTime;
}
Ad3.
This class handles the window creation, and pixel format settings,
and few other things related to the window itself - nothing else,
but it also needs to utilize CLogManager - to dump few informations
for debug purposes.
Now the question is:
When a CLogManager constructor is called, class generates a unique filename that is:
m_sFileName="data/logs/enginelog_%i%i%i.txt"; // hour, minute, second
CEngine class in the Init method does:
m_pLogManager = new CLogManager;
and later on it uses it with m_pLogManager->Write(....) to log events.
That's ok for CEngine, but i would like to use the same functionality
in CWindowGL class and here is the question.
I would like my code to share CLogManager across :
CEngine
CWindowGL
...
...
...
and few others that i'll implement.
I can't do this by adding "Instance()" type of method like:
static CLogManager &Instance()
{
static CLogManager s_instance;
return s_instance;
}
and calling:
CLogManager::Instance().Write(" LOG MESSAGE ");
As this would cause my CLogManager to generate new filename each time when a
constructor is called.
Do i have to
extern CEngine *Engine;
somewhere to call
Engine->Log(" LOG MESSAGE ")
wrapper everytime or there is something else i can stick to?
I know it is more like a 'code-design' question, but i would like to see
how do you guys handle such things.
Normally i would do this with extern, but that would require me to check
m_pLogManager!=NULL within a wrapper function to a private member - and just
don't know if that's OK.
Maybe there's some other - better approach?
I will be adding few other classes like. TexturesManager - and would like this class to
store the actual size of textures loaded and so on, so this would also require me to
not to call Instance() to class each time the texture is called - as this would create/destruct the class without storing the needed size / array of textures already loaded...
Uff..
Thanks, hope this is clear.
I can't do this by adding "Instance()" type of method as this would cause my CLogManager to generate new filename each time when a constructor is called.
Actually no, the constructor would be called only once during your program lifetime. The singleton pattern is what you most likely want for your logging class.
What you'll generally find in these situations is a static set of methods that use a singleton underneath. All consumers call the static method which returns the one, single, instance of your logger, which you then call methods on.
I've got a class outputInterface; that should handle the output (to files) of some data. The data is contained in objects of some custom classes, say dataClassA and dataClassB, that all derive from a common base class dataClassBase.
Now I want the data to be written to different files according to its type. So data of type dataClassA should go to fileA, data of type dataClassB should go to fileB and so on. As this output happens very often I would like the file handles (fileA and fileB) to stay open, i.e. I don't want to open and close the files for the output of each piece of data. One outputInterface object can be expected to exist all the time.
So what I would like to achieve is something like this:
Dynamically associate data of type dataClassA with the file handle fileA etc.
When receiving data of type dataClassA check whether fileA is already connected to a file, if not, open the file.
How can I get this behavior (or least something similar / better)?
I've been thinking of making the file handles static members of dataClassA and dataClassB (or the base class dataClassBase?). But then, how do I take care of closing the files? I would have to somehow keep track of the data types that have actually been used (the files that have actually been opened).
Try something like this:
#ifndef OUTPUTINTERFACE?H
#define OUTPUTINTERFACE?H
#include <string>
#include <fstream>
#include <map>
class DataClass
{
public:
virtual bool WriteData(std::ofstream& FStream) = 0;
};
class DataClass1 :
public DataClass
{
virtual bool WriteData(std::ofstream& FStream)
{
FStream << "teletubbies";
}
};
class DataClass2 :
public DataClass
{
virtual bool WriteData(std::ofstream& FStream)
{
FStream << "garbage";
}
};
class OutputInterface
{
public:
OutputInterface()
{
}
~OutputInterface()
{
//Release stream pointers
}
template<typename T>
bool WriteData(T& Data)
{
std::string dClassUID = std::string(typeid(T).name);
tFStreamMap::iterator it this->streamMap.find(dClassUID);
std::ofstream* stream = NULL;
if(it != streamMap.end())
{
stream = it->second;
}
else
{
stream = new std::ofstream();
stream->open(dClassUID + ".txt");
streamMap.insert(std::make_pair(dClassUID, stream));
}
Data.WriteData(stream);
}
private:
typedef std::map<std::string, std::ofstream*> tFStreamMap;
tFStreamMap streamMap;
};
#endif
This is just a prove of concept and can be optimized in many ways.
I would rather stick with overloaded functions than with runtime type checks.
This is fairly easy to implement in C++11, using an
std::map<std::type_index, std::ostring*> outputMap. (In C++03, you'll have to
implement the equivalent of std::type_index yourself.) You get the
output stream using outputMap[typeid(*data)]. The only problem is
getting the streams into the map to begin with: you can do something
like:
std::ostream*& destPtr = outputMap[typeid(*data)];
if ( destPtr == NULL ) {
destPtr = new std::ofstream("...");
}
std::ostream& dest = *destPtr;
But from where do you get the filename?
There's also the question of when you close the streams: you can't
normally close an output stream in a destructor, since closing an output
stream is an operation which can fail, and you need to detect and react
to that failure. Probably with an exception, which is why you don't
want to do it in a destructor.
Since the "data" part comes from dataClassBase, you can make a virtual/pure-virtual function 'WriteData` in this class, and let derive class implement it.
The class outputInterface may take objects of type dataClassBase and would directly call WriteData. Other than WriteData you may also add other virtual functions in dataClassBase
You did not mention relationship between outputInterface and dataClassBase