C++: function to append file, called within other functions - c++

So, I am trying to log information about the status of the c++ project code in a text file. The program terminates unexpectedly, so I need to append the file as I go rather than storing info in an array along the way. I wanted to call the function to write to the file from within other functions, eventually in the other c++ files as well.
The code is a huge project that has many files and the "main()" technically exists in a separate file from all of the functions that are called throughout the function of the code (therefore not a useful file for me). My plan was to open the file in the setup() function, and then call the function within other functions along the way. Just in case I did not explain the setup of the code well enough, here is the link to the file I am trying to add to: https://github.com/cstracq2/ardupilot/blob/master/ArduCopter/ArduCopter.cpp
I have seen other notes on what may help, but I am not that familiar with c++ and I don't know what most of it means. From what I saw, this is one of the ways I tried, and it is failing to compile.
#include "<existing header>.h"
#include <fstream>
#include <iostream>
void log_data( ofstream &datafile, int value);
void <>::function1()
{ ....<stuff that was already there>
log_data( datafile, <value> );
}
void <>::function2()
{ ....<stuff that was already there>
log_data( datafile, <value> );
}
void setup()
{ ....<stuff that was already there>
ofstream datafile;
datafile.open("data_log_file.txt");
}
void log_data( ofstream &datafile, int value)
{
data_file << value << endl;
}
If there is any advice that you could give me, I would really appreciate it.

In your case I would suggest to use the Singleton Pattern. Here is an example of how you could do it:
class Logger
{
std::ifstream logF;
static Logger *s_instance;
Logger(std::string &path)
{
logF.open(path, std::ios_base::in);
}
public:
void log_data(int val)
{
logF << val << std::endl;
}
static void create_instance(std::string &path)
{
s_instance = new Logger(path);
}
static Logger *instance()
{
return s_instance;
}
};
Now you can just include the header with the class def and call something like:
Logger::instance()->log_data(<value>);
And do not forget to init the class before calling the static method (somewhere in main for instance):
Logger::create_instance(<path>);
Of course, you can just make it easier by hard-coding a value for your path, but if the path changes you'll have to re-compile everything.
Or just use something already implemented like log4cpp

Ah yes now that you mentioned the use of datafile in other function I see the error: The variable datafile is a local variable inside the setup function.
It should either be a member variable or possible a global variable.

Related

Using method from class in another .h file in c++

I'm new in C++, and have been given a (relatively) complex piece of code.
I want to call a function transmit() from a .h file in another .c file.
The transmit() is in the file serviceUart.hpp which content looks like this:
serviceUart.hpp
class ServiceUart
{
public:
ServiceUart();
void ioConfig(); // sets io HW ports and pins. Only needed at first boot
void ioInit(); //
bool readTrigger();
bool detectConnection() {return (m_rxPin.get()|| m_enabled);}
bool startup();
bool transmit(const char* s, uint16_t length, bool wait = false);
The file drvr.cpp is where I try calling the function. A snippet of what I think is relevant from that file looks like this:
drvr.cpp
#include "EHS5_drv.hpp"
char debug[] = "I got to here!";
transmit(debug,true);
I tried serviceUart.transmit and serviceUart::transmit, but no matter what I try, I get the error code `#20 identifier "transmit" is undefined". I guess I'm misunderstanding the syntax?
Method bool transmit(const char* s, uint16_t length, bool wait = false); is defined in ServiceUart. You have to create an object of ServiceUart class and then call method transmit()
char debug[] = "I got to here!";
ServiceUart obj;
obj.transmit(debug,true);
Or with new
ServiceUart* obj = new ServiceUart();
obj->transmit(debug,true);
delete obj;
Don't forget to delete obj.
You probably want:
char[] debug = "I got here";
ServiceUart serviceObg;
obj.transmit(debug, true);

How to read data from a file from within a function

I want to make my code more efficient, specifically the reading of data from a text file. Here is a snapshot of what it looks like now:
values V(name);
V.population = read_value(find_line_number(name, find_in_map(pop, mapping)));
V.net_growth = read_value(find_line_number(name, find_in_map(ngr, mapping)));
... // and so on
Basically, the read_value function creates an ifstream object, opens the file, reads one line of data, and closes the file connection. This happens many times. What I want to do is to open the file once, read every line that is needed into the struct, and then close the file connection.
Here is the creating values struct function with parameters:
static values create_struct(std::string name, std::map<std::string, int> mapping) {
values V(name);
V.population = read_value(find_line_number(name, find_in_map(pop, mapping)), file);
V.net_growth = read_value(find_line_number(name, find_in_map(ngr, mapping)), file);
// more values here
return V;
}
The function that calls create_struct is shown below:
void initialize_data(string name) {
// read the appropriate data from file into a struct
value_container = Utility::create_struct(name, this->mapping);
}
I am thinking of instead defining the ifstream object in the function initialize_data. Given what is shown about my program, would that be the best location to create the file object, open the connection, read the values, then close the connection? Also, would I need to pass in the ifstream object into the create_values struct, and if so, by value, reference or pointer?
The short answer is to create your ifstream object first and pass it as reference to your parser. Remember to seek the stream back to the beginning before you leave your function, or when you start to read.
The RAII thing to do would be to create a wrapper object that automatically does this when it goes out of scope.
class ifStreamRef{
ifStreamRef(std::ifstream& _in) : mStream(_in){}
~ifStreamRef(){mStream.seekg(0);}
std::ifstream& mStream;
}
Then you create a wrapper instance when entering a method that will read the fstream.
void read_value(std::ifstream& input, ...){
ifStreamRef autoRewind(input);
}
Or, since the Ctor can do the conversion...
void read_value(ifStreamRef streamRef, ...) {
streamRef.mStream.getLine(...);
}
std::ifstream itself follows RAII, so it will close() the stream for you when your stream goes out of scope.
The long answer is that you should read up on dependency injection. Don't create dependencies inside of objects/functions that can be shared. There are lots of videos and documents on dependency injection and dependency inversion.
Basically, construct the objects that your objects depend on and pass them in as parameters.
The injection now relies on the interface of the objects that you pass in. So if you change your ifStreamRef class to act as an interface:
class ifStreamRef{
ifStreamRef(std::ifstream& _in) : mStream(_in){}
~ifStreamRef(){mStream.seekg(0);}
std::string getLine(){
// todo : mStream.getLine() + return "" on error;
}
bool eof() { return mStream.eof(); }
std::ifstream& mStream;
}
Then later on you can change the internal implementation that would take a reference to vector<string>& instead of ifstream...
class ifStreamRef{
ifStreamRef(std::vector<string>& _in) : mStream(_in), mCursor(0){}
~ifStreamRef(){}
std::string getLine(){
// todo : mStream[mCursor++] + return "" on error;
}
bool eof() { return mCursor >= mStream.size(); }
std::vector<string>& mStream;
size_t mCursor;
}
I have oversimplified a few things.

Writing to both terminal and file c++

I found this question answered for Python, Java, Linux script, but not C++:
I'd like to write all outputs of my C++ program to both the terminal and an output file. Using something like this:
int main ()
{
freopen ("myfile.txt","w",stdout);
cout<< "Let's try this";
fclose (stdout);
return 0;
}
outputs it to only the output file named "myfile.txt", and prevents it from showing on the terminal. How can I make it output to both simultaneously? I use visual studio 2010 express (if that would make any difference).
Thanks in advance!
Possible solution: use a static stream cout-like object to write both to cout and a file.
Rough example:
struct LogStream
{
template<typename T> LogStream& operator<<(const T& mValue)
{
std::cout << mValue;
someLogStream << mValue;
}
};
inline LogStream& lo() { static LogStream l; return l; }
int main()
{
lo() << "hello!";
return 0;
}
You will probably need to explicitly handle stream manipulators, though.
Here is my library implementation.
There is no built in way to do this in one step. You have to write the data to a file and then write the data out on screen in two steps.
You can write a function that takes in the data and the filename and does this for you, to save you time, some sort of logging function.
I have a method to do this, and it is based on a subscriber model.
In this model all your logging goes to a "logging" manager and you then have "subscribers" that decide what to do with the messages. Messages have topics (for me a number) and loggers subscribe to one or more topic.
For your purpose, you create 2 subscribers, one that outputs to the file and one that outputs to the console.
In the logic of your code you simply output the message, and at this level not need to know what is going to be done with it. In my model though you can check first if there are any "listeners" as this is considered cheaper than constructing and outputting messages that will only end up in /dev/null (well you know what I mean).
One way to do this would be to write a small wrapper to do this, for example:
class DoubleOutput
{
public:
// Open the file in the constructor or any other method
DoubleOutput(const std::string &filename);
// ...
// Write to both the file and the stream here
template <typename T>
friend DoubleOutput & operator<<(const T& file);
// ...
private:
FILE *file;
}
To have a class instead of a function makes you use the RAII idiom (https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization)
To use it:
DoubleOutput mystream("myfile");
mystream << "Hello World";

Using same variable in two functions

I have two functions read() and write(). I read a file in the read() function and store a line in the header in a variable. Now i want the write() function to write that same line to a new file. But how can i use the same variable or information from the other function? What is the way to do this?
Here is some info about the code:
After including necessary files, it says this
HX_INIT_CLASS(HxCluster,HxVertexSet);
The name of the class is HxCluster and it would be great if someone can tell me why it is not like we define classes in the simple way: class class_name {};
The I have many functions out of which two are read() and write(). They both take one argument only which is the file to be read and the file to be written to in the respective cases. I don't know if writing the code for that will help here.
If I understood you well, this is just what in C++ the structures/classes/objects are for. For example:
class FileLineWriter
{
public:
FileLineWriter();
void read(istream& inputfile);
void write(ostream& putfile);
private:
string line_of_text;
};
void FileLineWriter::read(istream& s)
{
// s >> this->line_of_text; // possible, but probably will not do what you think
getline(s, this->line_of_text);
}
void FileLineWriter::read(ostream& s)
{
s << this->line_of_text;
}
...
FileLineWriter writer;
writer.read(firstfile);
writer.write(secondfile);
note that the above is NOT a working code. It is just a sample. You will have to fix all typos, missing namespaces, headers, add stream opening/closing/error handling, etc.
You return the variable from read and pass it as a parameter to write. Something like this
std::string read()
{
std::string header = ...
return header;
}
void write(std::string header)
{
...
}
std::string header = read();
write(header);
Passing information between functions is a basic C++ skill to learn.
If I have understood this right then I would suggest that you save the info on the variable to a string or an int depending on what kind of info it is.
I would also recommend to always include some code for us to be able to give you some more help
You can either make write take an argument, void write(std::string text) or you can store the string you read as a global variable std::string text at the top of your .cpp file, text = ... in your read function (replace ... with ifstream or whatever you use) and then write text in your write funcion.
Sure,
Use pointers!
void main(){
char* line = malloc(100*sizeof(char));
read_function (line);
write_function (line);
}
void read_function(char* line){
.... read a line
strcpy (line, the_line_you_read_from_file);
}
void write_function (char* line){
fprintf (fp,"%s", line);
}

Fstream Initialization in a Class - Checking if File Opened

Example:
//Header File
class Example
{
private:
fstream InputObject;
public:
Example();
}
//Implementation File
Example::Example():InputObject("file_name.txt", ios::in) {}
From what I've read so far from similar questions, the only way, in the "older" version of C++, for initializing an fstream object in a class is to do so via member list initialization shown above.
Question:
If that really is the "only" way of initializing an fstream object in a class, what do we do if the file should fail to open?
Normally I'd run the fstream object through a check to make sure it opened properly, but this doesn't seem possible in this case. Also, even if I could, how could I reinitialize the object if it failed to do so the first time through?
#define WIN32_LEAN_AND_MEAN // This makes it so it doesn't look through libs that are not included when running
#include <fstream> //To Read write to files, to be able to
#include <iostream> // The basic stuff, cout, cin, etc.
using namespace std; // the capability of typing cout instead of std::cout
int main() // our main loop
{
fstream InputObject; // declaring InputObject as something that can write to a file
if(!Inputobject.open("File Name Here") // if it cant open the file
{
cout << "File not Open" << endl; // then write to console, " File not Open"
}
return 0;
system("pause");
}
You want to find out if the file is open, so using ! before the functio for opening file means , not open, so an if statement with !InputObject.open, will check if it is not open, if that is true, do something, so cout << "File is not open" will tell u if it is open or not.
From what I've read so far from similar questions, the only way, in the "older" version of C++, for initializing an fstream object in a class is to do so via member list initialization shown above.
That's not strictly true.
It is probably the preferred way of doing it. But you don't need to do it that way. And a failure simply sets the state to failed that can then be tested in the body of the constructor.
If that really is the "only" way of initializing an fstream object in a class
No.
what do we do if the file should fail to open?
Test and re-try in the body of the constructor.
Normally I'd run the fstream object through a check to make sure it opened properly, but this doesn't seem possible in this case. Also, even if I could, how could I reinitialize the object if it failed to do so the first time through?
There are standard API to reset the state of a stream after a failure.
Example::Example()
:InputObject("file_name.txt", std::ios::in)
{
if (!InputObject) {
InputObject.clear();
InputObject.open("AlternativeFile", std::ios::in)
}
}