I've a structure like in below:
std::list -> Includes list of objects in type of VolataliteAnalyzer *(Which is my custom class) -> VolataliteAnalyzer object keeps a ofstream object as in below code. And I'm calling the below method to write appropriate files
void VolataliteAnalyzer::writeToFile (unsigned long orderBookId,double volatalite,double currentWarrantPrice,double stockPrice,double expireDate,double strikePrice)
{
logger.logMessage(new MessageInfoLog(std::string(__PRETTY_FUNCTION__)+" Writing File For :"+std::to_string(orderBookId)));
if (!warrantFile.is_open()) {
std::string filePath = std::string(FILE_NAME)+std::string("_")+std::to_string(orderBookId)+std::string(FILE_EXT);
warrantFile.open (filePath,std::ios_base::app);
logger.logMessage(new MessageInfoLog(std::string(__PRETTY_FUNCTION__)+" Creating File:"+filePath));
}
warrantFile << this->getCurrentDate()+DELIMETER+std::to_string(volatalite)+DELIMETER+std::to_string(currentWarrantPrice)+DELIMETER+std::to_string(stockPrice)+DELIMETER+std::to_string(expireDate)+DELIMETER+std::to_string(strikePrice)+"\n";
}
However when I call this method , for different objects in the array , it always writes to same file . But instead it should write to unique files for each object in array. I've tested it many times but wasnt able to understand the reason. I suspected that if ofstream objects are singleton or something like that?
class VolataliteAnalyzer {
public:
double selectedVolatalite=0;
VolataliteAnalyzer();
void writeToFile(unsigned long orderBookId,double volatalite,double currentWarrantPrice,double stockPrice,double expireDate,double strikePrice);
void finishWriting();
bool loadFromFile(unsigned long orderBookId);
void getSelectedVolatalite(int dayCount);
private:
Logger& logger;
std::ofstream warrantFile;
std::ifstream warrantReader;
std::string getCurrentDate();
std::list<Volatalite *> dailyVolatalites;
Volatalite* getVolatalite(std::string date);
};
Related
As an example lets say I have a class called File. Now file can be opened as binary or text. My constructor is currently File(const char*filename). Let's suppose the implementation of open is completely different binary and text. How the heck do I construct this?
I thought about using a static function but I don't want to return a pointer. I could pass in a pointer but I rather not allow a class be constructed without actually initializing it.
I was thinking about having an enum or bool in the constructor but it feels 'wrong' to me (and the way I may do this). I could have a different class name for binary and text and have both inherit a base implementation (or the other implementation) even though the only difference is the constuctor.
What's the most idiomatic way of doing this in C++?
Add a flag
enum class open_mode
{
binary,
text
};
File(const char* filename, open_mode mode);
or use a tag
struct binary_tag { };
struct text_tag { };
File(const char* filename, binary_tag);
File(const char* filename, text_tag);
Two idiomatic ways are a factory function (nothing forces you to return a pointer), or tag dispatching (which is used in the standard library, for example in std::variant).
// Factory functions
struct File {
static File openText(char const *filename);
static File openBinary(char const *filename);
};
// Tag dispatching
struct open_as_binary_t {} constexpr open_as_binary;
struct open_as_text_t {} constexpr open_as_text;
struct File {
File(char const *filename, open_as_binary_t);
File(char const *filename, open_as_text_t);
};
I could have a different class name for binary and text and have both
inherit a base implementation (or the other implementation) even
though the only difference is the constuctor.
Yes, in general, I can propose to use the polymorphism.
It is always clean, easy maintainable, extensible and understandable. Very flexible.
The best for creating something could be the factory design pattern.
Example:
class File{ protected: File(); ... }; // make constructor protected!
class BinFile : public File;
class TextFile : public File;
Then you could use it in the ordinary way:
File *f = new BinFile;
File *f = new TextFile;
Place all common stuff in class File
Implement any specific functionality per child class.
Then you could engage some factory method like:
File * OpenFile( String pathToFile, "TextFile" );
File * OpenFile( String pathToFile, "BinFile" );
In general, in this way, the code is very flexible.
Why not even simpler:
File(const char *filename,const char *mode)
{
fl=fopen(filename,mode);
//
}
And simply call with myFile = File("log.txt","rt");
I have the following:
class SpritesheetManager{
std::unordered_map<std::string,std::unordered_set<std::string>> _loadedFiles;
void addFileToFileListForSheet(std::string sheetprefix,std::string filename);
}
When adding files I do this:
void SpritesheetManager::addFileToFileListForSheet(std::string sheetprefix,std::string filename){
bool containsKey = (_loadedFiles.find(sheetprefix)!= _loadedFiles.end());
std::unordered_set<std::string> values;
if(!containsKey){
_loadedFiles[sheetprefix] = values;
}
_loadedFiles[sheetprefix].insert(filename);
}
Is there a better way to do this?
Using the fact that operator[] automatically default constructs and inserts a value if you try to access a key that does not exist, you can simplify your code to this:
void SpritesheetManager::addFileToFileListForSheet(std::string sheetprefix,std::string filename) {
_loadedFiles[sheetprefix].insert(filename);
}
Etienne de Martel's answer would simplify the code if you keep this data-structure.
However, if you don't need any functionality that's common to the sheet prefix (like going over all the files with the same prefix, etc), and just care about keeping multiple files with the same prefix, you could simplify your code considerably by using an unordered_multimap:
Header:
class SpritesheetManager {
std::unordered_multimap<std::string, std::string> _loadedFiles;
void addFileToFileListForSheet(std::string sheetprefix, std::string filename);
}
Implementation:
void SpritesheetManager::addFileToFileListForSheet
(std::string sheetprefix, std::string filename) {
_loadedFiles.insert(std::make_par(sheetprefix, filename));
}
I have something that looks like this
class RestaurantCheck
{
private:
static const int MENU_LENGTH = 10;
static const string menu[MENU_LENGTH] = {"Gumbo", "Shrimp", etc...}
Right off the bat, I have a problem. I know I can't initialize the data in the array as it is now, so I tried this ...
class RestaurantCheck
{
private:
static const int MENU_LENGTH = 10;
static const string menu[MENU_LENGTH];
void displayMenu();
public:
void showMenu()
{
RestaurantCheck thisMenu;
thisMenu.displayMenu();
}
void RestaurantCheck::displaymenu()
{
menu[0] = "Shrimp"
menu[1] = "Gumbo"
etc...
cout << menu[0]
etc...
However I am unable to store data in the array like that as well.
How the heck am I supposed to store data in this array? As part of the assignment, the array must be a const static, it must be in private, and the displayMenu must also be private, called by a public function.
I hope what I'm getting at is clear, if not I'll try to provide more information.
EDIT:
I can not edit anything from the instructors source file. The source file is already created, and he will be using his own (provided) to test both my class file and my header file. Thus it needs to be initiated outside of sourcefile.
You are falling into the same trap as many before you. Your array is const, so it must be initialized when declared. But you can not initialize static string arrays in the class body. What do you do? You initialize it outside!
like this:
in your .h file:
static const std::string menu[10];
in your .cpp file:
const std::string RestaurantCheck::menu[10] = {"Shrimp", "Calamari", "Listeria"};
Is this what you are looking for?
You can initialize static non scalar members, but this must be done outside the class:
#include <string>
class RestaurantCheck{
static const int MENU_LENGTH = 3;
static const std::string menu[MENU_LENGTH];
};
const std::string RestaurantCheck::menu[RestaurantCheck::MENU_LENGTH] = {"Gumbo", "Shrimp", "Jar" };
note the "init line" must be present only in one file, best place is some .cpp file that is compiled to object. Here is what I mean:
restaurantcheck.h - RestaurantCheck header
restaurantcheck.cpp - RestaurantCheck implementation (best place for "init line")
main.cpp - program (where main() is located)
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?
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