Passing std::ofstream object as argument to class method - c++

As previous questions have been answered, the way to pass a std::ofstream object as a function argument seems to be to instead pass a reference: std::ofstream&.
Whilst this solution compiles, the resulting output is not equivalent to creating an std::ofstream object within the method then calling write().
The code below does not give the correct output:
In main.cpp:
std::ofstream file(path + "output.stubs");
stub->writeRaw(file); //stub is a pointer to an object of class Stub
file.close();
In Stub.cpp:
void Stub::writeRaw(std::ofstream& file) {
file.write((char*)this, sizeof(*this));
}
The correct output is given by both changing Stub.cpp to:
void Stub::writeRaw(void) {
std::ofstream file(path + "output.stubs");
file.write((char*)this, sizeof(*this));
file.close();
}
or writing the object to the file in main instead of calling a class method.
Any help on this behaviour would be greatly appreciated!
EDIT
Some context for the class Stub:
Stub.hpp
#pragma once
#include <iostream>
#include <ios>
#include <fstream>
#include "constants.hpp"
#include "DataTypes.hpp"
class Stub {
private:
StubHeader header;
StubIntrinsicCoordinates intrinsic;
StubPayload payload;
public:
Stub(void);
virtual ~Stub(void);
StubHeader getHeader(void);
StubIntrinsicCoordinates getIntrinsicCoordinates(void);
StubPayload getPayload(void);
void setHeader(StubHeader stub_header);
void setIntrinsicCoordinates(StubIntrinsicCoordinates stub_intrinsic);
void setPayload(StubPayload stub_payload);
void print(void);
void writeRaw(std::ofstream& file);
};
And the relevant data types are defined as follows:
struct StubHeader {
uint8_t bx;
uint8_t nonant;
};
struct StubIntrinsicCoordinates {
uint8_t strip;
uint8_t column;
int crossterm;
};
struct StubPayload {
bool valid;
int r;
int z;
int phi;
int8_t alpha;
int8_t bend;
uint8_t layer;
bool barrel;
bool module;
};
EDIT 2
The (toy) code to read the stub is as follows:
std::ifstream r(path + "output.stubs");
Stub s;
r.read((char*)&s, sizeof(s));
s.print();
Only one stub is written to the file as this was a test of functionality. The print function for the Stub class is as follows:
void Stub::print(void) {
std::cout << "----- Header -----" << '\n';
std::cout << "bx: " << std::dec << (int)header.bx << '\n';
std::cout << "nonant: " << std::dec << (int)header.nonant << '\n';
std::cout << "----- Intrinsic Coordinates -----" << '\n';
std::cout << "strip: " << std::dec << (int)intrinsic.strip << '\n';
std::cout << "column: " << std::dec << (int)intrinsic.column << '\n';
std::cout << "crossterm: " << std::dec << (int)intrinsic.crossterm << '\n';
std::cout << "----- Payload -----" << '\n';
std::cout << "valid: " << std::boolalpha << payload.valid << '\n';
std::cout << "r: " << std::dec << (int)payload.r << '\n';
std::cout << "z: " << std::dec << (int)payload.z << '\n';
std::cout << "phi: " << std::dec << (int)payload.phi << '\n';
std::cout << "alpha: " << std::dec << (int)payload.alpha << '\n';
std::cout << "bend: " << std::dec << (int)payload.bend << '\n';
std::cout << "layer: " << std::dec << (int)payload.layer << '\n';
std::cout << "barrel: " << std::boolalpha << payload.barrel << '\n';
std::cout << "module: " << std::boolalpha << payload.module << "\n\n";
}
EDIT 3
For completeness and transparency, please find below the exact code for main.cpp:
int main(int argc, char const *argv[]) {
Geometry g;
g.generateModuleLUTs();
g.generateCorrectionLUTs();
std::vector<std::array<Stub*, PAYLOAD_WIDTH> > all_stubs;
std::vector<Module> modules = g.getData();
for (int i = 0; i < LINK_NUMBER; i++) {
LinkGenerator link_gen;
LinkFormatter link_formatter(link_gen.run());
StubFormatter stub_formatter(link_formatter.run(), i);
std::array<Stub*, PAYLOAD_WIDTH> stubs = stub_formatter.run(modules);
CoordinateCorrector coordinate_corrector(stubs);
all_stubs.push_back(coordinate_corrector.run());
}
std::ofstream f(path + "output.stubs");
all_stubs[0][0]->writeRaw(f);
all_stubs[0][0]->print();
std::ifstream r(path + "output.stubs");
Stub s;
r.read((char*)&s, sizeof(s));
s.print();
return 0;
}

The bug in the code was that I was not calling file.close() before constructing the std::ifstream object to read the file again. This was the cause of the unexpected behaviour.
Writing a class to file using this seems to be valid, although it is important that you are careful and know exactly what you want to write to a file.
Thank you to everyone who commented and helped to answer this question!

Related

Using stringstream's ignore

I am trying to use a stringstream as a buffer but I am unable to update the underlying streambuf :
#include <iostream>
#include <sstream>
int main () {
std::stringstream ss(std::ios_base::app|std::ios_base::in|std::ios_base::out); //ostringstream gives the same output
ss << "foo";
std::cout << "position get: " << ss.tellg() << std::endl;
std::cout << "position put: " << ss.tellp() << std::endl;
ss << "b";
std::cout << "position get: " << ss.tellg() << std::endl;
std::cout << "position put: " << ss.tellp() << std::endl;
char c;
ss >> c;
std::cout << "position get: " << ss.tellg() << std::endl;
std::cout << "position put: " << ss.tellp() << std::endl;
ss.ignore(1);
std::cout << "position get: " << ss.tellg() << std::endl;
std::cout << "position put: " << ss.tellp() << std::endl;
std::cout << ss.str() << std::endl;
return 0;
}
yields:
position get: 0
position put: 3
position get: 0
position put: 4
position get: 1
position put: 4
position get: 2
position put: 4
foob
Is it possible to force a reallocation of the streambuf underlying object ? If not, is this reallocation automatic and in which circumstance is it triggered ?
I know I can use ss.str to change the underlying buffer. But it is a pain to use it to manually update the buffer to a substr's version.
Note: I am doing a school project and must compile to c++98, hence, if you have a solution which is comptabible, it would be much appreciated.

How to pass cin to a function?

I am learning about different stream state flags/functions in C++ such as good(), goodbit, bad(), badbit and so on. While testing with std::cin, I am unable to pass cin as an argument to a function (the compiler shows a lot of errors)
#include <iostream>
#include <sstream>
void print_state (const std::istream& stream) {
std::cout << " good()=" << stream.good();
std::cout << " eof()=" << stream.eof();
std::cout << " fail()=" << stream.fail();
std::cout << " bad()=" << stream.bad();
}
int main() {
std::cin.clear (std::ios::goodbit);
std::cout << "goodbit: " << print_state(std::cin) << std::endl;
std::cin.clear (std::ios::eofbit);
std::cout << "eofbit: " << print_state(std::cin) << std::endl;
std::cin.clear (std::ios::failbit);
std::cout << "failbit: " << print_state(std::cin) << std::endl;
std::cin.clear (std::ios::badbit);
std::cout << "badbit: " << print_state(std::cin) << std::endl;
return 0;
}
Desired output:
goodbit: good()=1 eof()=0 fail()=0 bad()=0
eofbit: good()=0 eof()=1 fail()=0 bad()=0
failbit: good()=0 eof()=0 fail()=1 bad()=0
badbit: good()=0 eof()=0 fail()=1 bad()=1
I know I can call the function directly with cin, such as std::cin.good(), but I want to know how can I pass cin as an argument to a function.
Edit:
I get a LOT of errors during compilation. An example:
F:\cpp_programming\stream_states.cpp: In function 'int main()':
F:\cpp_programming\stream_states.cpp:13:27: error: no match for 'operator<<' (operand types are 'std::basic_ostream<char>' and 'void')
std::cout << "goodbit: " << print_state(std::cin) << std::endl;
~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
Since print_state does not return a value, it cannot be used with the insertion operator <<. The simplest way to correct this, is to call print_state on its own.
print_state(std::cin);
The corrected code is given below:
#include <iostream>
#include <sstream>
void print_state (const std::istream& stream) {
std::cout << " good()=" << stream.good();
std::cout << " eof()=" << stream.eof();
std::cout << " fail()=" << stream.fail();
std::cout << " bad()=" << stream.bad();
}
int main() {
std::cin.clear (std::ios::goodbit);
std::cout << "goodbit: "; print_state(std::cin); std::cout << std::endl;
std::cin.clear (std::ios::eofbit);
std::cout << "eofbit: "; print_state(std::cin); std::cout << std::endl;
std::cin.clear (std::ios::failbit);
std::cout << "failbit: "; print_state(std::cin); std::cout<< std::endl;
std::cin.clear (std::ios::badbit);
std::cout << "badbit: "; print_state(std::cin); std::cout << std::endl;
return 0;
}
To answer my own question
cin can be passed to a function as a function argument, such as:
functionName(std::cin);

c++ csv reader with the functionality of the python csv.dictreader

is there any library or example for reading a csv file in C++ like the csv module in Python?
What I need is a function to read a csv file and put each column element of a row in a map with the header name as the key value.
I can answer myself. I wrote a CSVDict class.
#include <iterator>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
#include <map>
class CSVDict {
public:
CSVDict(std::string fileName, int headerRow) {
file = std::ifstream(fileName);
for (int i = 0; i < headerRow; i++){ readNextRow(file); }
m_header = m_data;
}
std::string const& operator[](std::size_t index) const {
return m_data[index];
}
std::string const& operator[](std::string index) const {
return m_dataMap.find(index)->second;
}
bool readNextRowMap() {
readNextRow(file);
if (!file) return false;
m_dataMap.clear();
auto it_data = m_data.begin();
for (auto it = m_header.begin(); it != m_header.end(); ++it) {
m_dataMap[*it] = *it_data;
++it_data;
}
return true;
}
private:
void readNextRow(std::istream& str) {
std::string line;
std::getline(str, line);
if (!str) return;
std::stringstream lineStream(line);
std::string cell;
m_data.clear();
while (std::getline(lineStream, cell, ';')) {
m_data.push_back(cell);
}
}
std::vector<std::string> m_data;
std::vector<std::string> m_header;
std::map<std::string, std::string> m_dataMap;
std::ifstream file;
};
int main()
{
CSVDict dict("1.csv", 2);
while (dict.readNextRowMap()) {
std::cout << dict[0] << " " << dict[1] << " " << dict[2] << " " << dict[3] << " " << dict[4] << " " << dict[5] << " " << dict[6] << "\n";
}
CSVDict dict1("1.csv", 2);
dict1.readNextRowMap();
std::cout << dict1["ipField"] << " " << dict1["mdBeamEnergy"] << " " << dict1["mdBeamCurrent"] << " " << dict1["mcoBeamSizeId"] << " " << dict1["mdGantryAngle"] << " " << dict1["miLayerNumber"] << "\n";
dict1.readNextRowMap();
std::cout << dict1["ipField"] << " " << dict1["mdBeamEnergy"] << " " << dict1["mdBeamCurrent"] << " " << dict1["mcoBeamSizeId"] << " " << dict1["mdGantryAngle"] << " " << dict1["miLayerNumber"] << "\n";
dict1.readNextRowMap();
std::cout << dict1["ipField"] << " " << dict1["mdBeamEnergy"] << " " << dict1["mdBeamCurrent"] << " " << dict1["mcoBeamSizeId"] << " " << dict1["mdGantryAngle"] << " " << dict1["miLayerNumber"] << "\n";
dict.readNextRowMap();
std::cout << dict[0] << " " << dict[1] << " " << dict[2] << " " << dict[3] << " " << dict[4] << " " << dict[5] << " " << dict[6] << "\n";
return 0;
}
Example csv file:
#VALUES;;;;;;
ipField;mdBeamEnergy;mdBeamCurrent;mcoBeamSizeId;mdGantryAngle;miLayerNumber;mbRoomSwitchingLayer
24.30815;172.152971;24.30815;4;65;1;1
24.30815;172.152971;24.30815;4;65;2;0
24.30815;172.152971;24.30815;4;65;3;0
24.30815;172.152971;24.30815;4;65;4;0
24.30815;172.152971;24.30815;4;65;5;0
24.30815;172.152971;24.30815;4;65;6;0
24.30815;172.152971;24.30815;4;65;7;0
24.30815;172.152971;24.30815;4;65;8;0
usage (see main function in example):
class constructor needs to have the csv filename and the csv header line number
every readNextRowMap gets the values of the next line in the csv file
you can address the values either by number index or by header name
downside:
csv file has to have a header line

Function reads input and runs function twice

I am working on a function in a program to read an input from a user then, the function will check to see if that function exists and then runs it, but it is very buggy and the functions meant to be run, run twice.
//functions with a int and a string
std::map<std::string, std::function<void(int, string)>> functionsIS = {
{"printWordWithNumber", numberPlusWord},
};
//functions with no parameters
std::map<std::string, std::function<void()>> functionsNI = {
{"Help", userHelp},
};
void CommandCheck(std::string command){
int paramInt;
string paramString;
for (int i = 0; i < functionsIS.size(); i = i++){
if (functionsIS[command]){
std::cout << "Accessed '" << command << "' reading requirements..." << std::endl;
std::cout << "Enter paramater one (integer) : ";
std::cin >> paramInt;
std::cout << std::endl<<"Enter paramater two (string)" << std::endl;
std::cin.ignore();
std::getline(std::cin,paramString);
std::cout << "running..." << std::endl;
functionsIS[command](paramInt,paramString);
}
}
for (int i = 0; i < functionsNI.size(); i = i++){
if (functionsNI[command]){
std::cout << "Accessed '" << command << "' running..." << std::endl;
functionsNI[command]();
}
}
}
Here is version for you to run:
In source:
#include <iostream>
#include <map>
#include <windows.h>
#include <string>
#include <vector>
#include <map>
#include <functional>
#include "userFunctions.h"//header file for functions
using namespace std;
std::string input;
//functions with a int and a string
std::map<std::string, std::function<void(int, string)>> functionsIS = {
{ "printWordWithNumber", numberPlusWord },
};
//functions with no parameters
std::map<std::string, std::function<void()>> functionsNI = {
{ "Help", userHelp },
};
void CommandCheck(std::string command){
int paramInt;
string paramString;
for (int i = 0; i < functionsIS.size(); i = i++){
if (functionsIS[command]){
std::cout << "Accessed '" << command << "' reading requirements..." << std::endl;
std::cout << "Enter paramater one (integer) : ";
std::cin >> paramInt;
std::cout << std::endl << "Enter paramater two (string)" << std::endl;
std::cin.ignore();
std::getline(std::cin, paramString);
std::cout << "running..." << std::endl;
functionsIS[command](paramInt, paramString);
}
}
for (int i = 0; i < functionsNI.size(); i = i++){
if (functionsNI[command]){
std::cout << "Accessed '" << command << "' running..." << std::endl;
functionsNI[command]();
}
}
}
int main(){
do{
std::cout << "Waiting For Command..." << std::endl;
cin >> input;
CommandCheck(input);
} while (input != "end");
return 0;
}
Create a header file called "functions" and paste this:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
void numberPlusWord(int number, std::string word){
std::cout << word << std::endl;
std::cout << number << std::endl;
}
void userHelp(){
std::cout << "I can help!" << std::endl;
}
There are a couple of problems with your code that would cause problems. The first is that you are iterationg through the function map and if the command exists you are calling it. The problem is that you are checking for the same command on every iteration so if the map contains more than one element the command will be called for each of them. You can resolve this by removing the for loop and using the find function of the map to determine if the command exists.
The second problem is that if the command does not exist an element will be created in the map for it. The if statement below will automatically insert an element using command as the key.
if(functionsIS[command]) { /*...*/}
The following update to your code will correct the problem.
void CommandCheck(std::string command)
{
int paramInt;
string paramString;
if (functionsIS.find(command) != functionsIS.end())
{
std::cout << "Accessed '" << command << "' reading requirements..." << std::endl;
std::cout << "Enter paramater one (integer) : ";
std::cin >> paramInt;
std::cout << std::endl << "Enter paramater two (string)" << std::endl;
std::cin.ignore();
std::getline(std::cin, paramString);
std::cout << "running..." << std::endl;
functionsIS[command](paramInt, paramString);
}
else if (functionsNI.find(command) != functionsNI.end())
{
std::cout << "Accessed '" << command << "' running..." << std::endl;
functionsNI[command]();
}
}

Sequential file initialization unexpected behavior

I'm trying to initialize a file with 100 empty records with the code below:
void initializeInventory() {
std::ofstream out("hardware.dat", std::ios::binary);
Hardware h;
for (int i = 0; i < 100; ++i) {
h.ID = i;
h.name = "try"; // std::string();
h.quantity = 0;
h.price = 0;
h.notes = "try2"; //std::string();
out.write(reinterpret_cast<const char*>(&h), sizeof(Hardware));
}
out.close();
}
But when I try to print them out, it always print only 25 elements or crashes.
This is the function to print out elements:
void readInventory() {
std::ifstream in("hardware.dat", std::ios::in);
std::cout << std::setiosflags(std::ios::left) << std::setw(4) << "ID"
<< std::setw(16) << "Name"
<< std::setw(11) << "Quantity"
<< std::setw(10) << std::resetiosflags(std::ios::left)
<< "Price"
<< std::setw(50) << "Notes" << '\n';
Hardware h;
while (!in.eof()) {
in.read(reinterpret_cast<char*>(&h), sizeof(Hardware));
//if (!in.eof())
printOut(std::cout, h);
}
in.close();
}
void printOut(std::ostream &output, const Hardware& h) {
output << std::setiosflags(std::ios::left) << std::setw(4) << h.ID
<< std::setw(16) << h.name
<< std::setw(11) << h.quantity
<< std::setw(10) << std::setprecision(2)
<< std::resetiosflags(std::ios::left)
<< std::setiosflags(std::ios::fixed | std::ios::showpoint )
<< h.price
<< std::setw(50) << h.notes << '\n';
}
I also noted that if I increase the number of cycles in the for (I tried putting 400 instead of 100) the file hardware.dat seems to grow, so I thought that should be a problem in the print function. Any idea? Is there something I'm missing?
Thanks in advance.
It would be the best to overload the operator <<
friend ostream& operator<<(ostream& out, const Hardware& h) // output
{
out << "(" << h.id() << ", " << h.whatever() << ")";
return out;
}
and read the file line by line to the Hardware object.
By the way, overloading the input operator >> is also possible.